一片冰心在玉壶

那时我们有梦,关于文学,关于爱情,关于穿越世界的旅行, 如今我们深夜饮酒,杯子碰到一起,都是梦破碎的声音. 交往都是初逢,爱情都在心里,往事都在梦中, 希望都带着注释,信仰都带着呻吟. 总有善意的光逃避现世的繁琐而寻找片刻的安宁, 也许,就是你凝视这里的眼睛

博客园 首页 联系 订阅 管理
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mount.h>
#include <unistd.h>
#include <pthread.h>
//setMsg
#define TRUE              1
#define FALSE             0
/*
下面是我根据网上一篇文章的思路整理的来的,以及测试验证通过,将其中的打印换成标准的C打印就可以直接拿来跑。
目前只是验证了U盘,没有进行硬盘测试,以及一些异常测试。但是证明整个通道是OK的。该代码的作用是:在机顶盒上
检测有USB的插拔,即可通知到应用,这个不难办到,关键是插拔之后应用还要能够访问U盘目录,所以就要进行手动的
mount 和umount操作。
*/
#define FILE_DEV_CHECK             "/proc/scsi/scsi"                                          //用来检测设备数和类型
#define FILE_MOUNT_CHECK        "/proc/mounts"                                          //用来检测设备是否被mount
#define FILE_DISC_PARTS_CHECK   "/proc/partitions"                                   //用来检测设备的分区情况
#define FILE_DEV_PART_TEMPL     "/dev/scsi/host%d/bus0/target0/lun0/"   //具体的设备
#define USB_CDROM_MP                  "/opt/cdrom"
#define USB_DISK_MP                       "/opt/d"
#define FILE_DEV_STATU_TEMPL "/proc/scsi/usb-storage-%d/%d"   //用来检测某一设备是否在插入状态
#define MAX_NAME_LEN                   64
#define MAX_PART_NUM                  6   //最多运行6个分区
#define KK_FS_OK    1
#define KK_FS_FAIL   0
typedef struct s_scsi_usb_dev
{
    int type;                                        /*1 cdrom 2 disk */
    int index;                                       /*like host0 host1*/
    char file_statu[MAX_NAME_LEN];                    /*like "/proc/scsi/usb-storage-%d/%d"*/
    char devfile_parts[MAX_PART_NUM][MAX_NAME_LEN];   /*存储每个分区的设备文件*/
    char mount_path[MAX_PART_NUM][MAX_NAME_LEN];      /*与上面对应的mount点*/
    int part_num;                                    //4分区数
    struct s_scsi_usb_dev *next_dev;                 //4指向下一个设备
} SCSI_USB_DEV;

static SCSI_USB_DEV *f_first_dev = NULL;
static int insert = FALSE;
static int  find_attached = FALSE;
static int is_manual_umount = 1;

static void CLEAR_DEV(void);
static int CHECK_PARTS(SCSI_USB_DEV *dev);
static int ADD_DEV(SCSI_USB_DEV *dev);
static int INIT_DEV(SCSI_USB_DEV *dev, int index, char *type);
static int check_mount(SCSI_USB_DEV *dev);
static int do_mount(SCSI_USB_DEV *dev);
static int do_umount(SCSI_USB_DEV *dev);
static int process_dev(SCSI_USB_DEV *dev);
static int find_device(void);


//device opt function
static int ADD_DEV(SCSI_USB_DEV *dev)
{
    if(f_first_dev)
    {
        dev->next_dev = f_first_dev;
        f_first_dev = dev;
    }
    else
    {
        f_first_dev = dev;
        dev->next_dev = NULL;
    }
    return KK_FS_OK;
}

static int INIT_DEV(SCSI_USB_DEV *dev, int index, char *type)
{
    dev->index = index;
   sprintf(dev->file_statu, FILE_DEV_STATU_TEMPL, index, index);
    if (!strncmp(type, "CD-ROM"6))//cd-rom
    {
   
    }
    else//usb disk
    {
        dev->type = 2;
        dev->part_num = CHECK_PARTS(dev);
    }
    return KK_FS_OK;
}

/*
* 如果在/proc/scsi/scsi/中发现的设备是usb-storage,则进一步在/proc/partitions/中分析其所
* 包含几个分区,并将其记录下来dev->devfile_parts,mount路径也一并设置dev->mount_path
* 例如发现一个U盘,仅仅有一个分区,系统将其挂载在/dev/sda1/下,则可以将其mount路径设置成
* 用户可以访问的/tmp/usb/disk0/part0/下
*/
static int CHECK_PARTS(SCSI_USB_DEV *dev)
{
    int len = 0;
    int part_num = 0;
    char buf[1024] = {0};     //1024 is enough for save information of FILE partitions
    char hoststr[16] = {0};
    char *delim="\n";
    char *line = NULL;
    char *strtok_tmp_ptr = NULL;
    char *seek = NULL;
    char *seek_sd = NULL;      //USED FOR DEVICE MOUNTED ON SD*
    char *seek_hd = NULL;      //USED FOR DEVICE MOUNTED ON HD*
    char *part_blocks = NULL;
    FILE *fd = NULL;

    fd = fopen(FILE_DISC_PARTS_CHECK, "r"); //直接操作open打开系统文件
    if(fd != NULL)
    {
     //   printf("[%s]open file %s success\n",__FUNCTION__,FILE_DISC_PARTS_CHECK);
        len = fread(buf, 1sizeof(buf), fd);
        fclose(fd);
        if(len > 0)
        {
            line = strtok_r(buf, delim, &strtok_tmp_ptr);//以"\n"结束符来截断字符串
            while(line)
            {
                seek_sd = strstr(line, "sd");//成功找到sd后指针seek指向s, seek_sd[0] = 's', seek_sd[1] = 'd'
            
//    seek_hd = strstr(line, "hd");//成功找到hd后指针seek指向h, seek_hd[0] = 'h', seek_hd[1] = 'd'

                if (seek_sd)
                {
                    if(seek_sd[2] >= 'a' && seek_sd[2] <= 'z')
                    {
                        if(seek_sd[3] >= '1' && seek_sd[3] < '9')
                        {                    
                            printf("[%s]find device %s\n",seek_sd);
                            sprintf(dev->devfile_parts[part_num],"/dev/%s", seek_sd);
                            sprintf(dev->mount_path[part_num], USB_DISK_MP"/disk%d/part%d",dev->index, part_num);
                            part_num ++;
                            if (part_num == MAX_PART_NUM)
                            {
                                 break;//too many parts ignore
                            }
                        }
                    }
                }
         /*       if (seek_hd)
                {
                    if(seek_hd[2] >= 'a' && seek_hd[2] <= 'z')
                    {
                        if(seek_hd[3] >= '1' && seek_hd[3] < '9')
                        {
                        //    printf("[%s]find device %s\n",seek_sd);
                            sprintf(dev->devfile_parts[part_num],"/dev/%s", seek_hd);
                            sprintf(dev->mount_path[part_num], USB_DISK_MP"/disk%d/part%d",dev->index, part_num);
                            part_num ++;
                            if (part_num == MAX_PART_NUM)
                            {
                                 break;//too many parts ignore
                            }
                        }
                    }
                }
*/
                line = strtok_r(NULL, delim, &strtok_tmp_ptr);
            }
        }
    }
    else
    {
        perror(FILE_DISC_PARTS_CHECK);
    }
    return part_num;
}

/*
* 线程扫描时会不停的调用该接口去清除之前获取的设备信息
*/
static void CLEAR_DEV(void)
{
    SCSI_USB_DEV *cur_dev = f_first_dev;
    SCSI_USB_DEV *tmp_dev;
    while (cur_dev)
    {
        tmp_dev = cur_dev;
        cur_dev = cur_dev->next_dev;
        free(tmp_dev);
    }
    f_first_dev = NULL;
}


/*
* 打开"/proc/scsi/scsi" 里面会有如下信息,该接口通过轮询Host: scsi去查找有无插上设备
* 以及轮询Type 去查询设备类型
* Attached devices:
*
* Host: scsi0 Channel: 00 Id: 00 Lun: 00
*    Vendor: BENQ        Model: DVD-ROM 16X      Rev: A.DD
*    Type:   CD-ROM                           ANSI SCSI revision: 02
*
* Host: scsi1 Channel: 00 Id: 00 Lun: 00
*    Vendor: FUJITSU     Model: MHT2040AH         Rev: 0000
*    Type:   Direct-Access                    ANSI SCSI revision: 02
*
*
*/
static int find_device()
{
    FILE *fd = NULL;
    int len = 0;
    int dev_num = 0;
    char buf[1024] = {0};
    char *seek = NULL;
    SCSI_USB_DEV *new_dev = NULL;

    //clear exist device
    CLEAR_DEV();

    //add new device
    fd = fopen(FILE_DEV_CHECK, "r");//直接操作open系统文件/proc/scsi/scsi

    if(fd > 0)
    {
        /*
        * 如果没有任何设备接入,那么/proc/scsi/scsi中仅仅包含下列字符 "Attached devices:"
        * 文件长度为18。所以下面以20个字符来做判断。
        
*/
        len = fread(buf, 1sizeof(buf), fd);
        fclose(fd);
        if(len < 20 && find_attached == TRUE)
        {
            find_attached = FALSE;
      //      KK_ERROR("Device removed......\n");            
   
//         KKFS_Callback(KK_FS_DISK_REMOVED);
            return KK_FS_OK;
        }
        if (len > 0)
        {
            /*
            * 如果文件打开成功,而且长度大于20,表示里面是有设备记录的,如果find_attached标志之前是FALSE
            * 表示有新的动作:设备插入系统
            
*/
            if(len > 20 && find_attached == FALSE)
            {
                find_attached = TRUE;
           //     KK_ERROR("Device Inserted......\n");            
           
//     KKFS_Callback(KK_FS_DISK_INSERT);
            }
            seek = buf;
            while(seek && ((strlen(seek)) > 0))//jacky
            {
                seek = strstr(seek, "Host: scsi");//从seek 中查找"Host: scsi"的第一次出现,返回第一次出现的位置
                if(seek && (seek[0] == 'H'))
                {
                    seek += strlen( "Host: scsi");
                    seek = strstr(seek, "Type:");
                    if(seek && (seek[0] == 'T'))
                    {
                        seek += strlen("Type:");
                        while(*seek == ' ')
                        {
                            seek++;
                        }
                        new_dev = malloc(sizeof(SCSI_USB_DEV));

                        INIT_DEV(new_dev, dev_num, seek);
                        ADD_DEV(new_dev);      
                        dev_num ++;
                    }
                }
            }
      //      KK_INFO("dev_num = %d\n", dev_num);
        }
    }
    else
    {
        perror(FILE_DEV_CHECK);
    }
    return dev_num;
}


static int check_mount(SCSI_USB_DEV *dev)
{
    FILE *fd = NULL;
    int len = 0;
    int i = 0;
    char buf[1024] = {0};
    char *seek = NULL;

    fd = fopen(FILE_MOUNT_CHECK, "r");
    if(fd > 0)
    {
    //    KK_INFO("[%s]open file %s success\n",__FUNCTION__, FILE_MOUNT_CHECK);
        len = fread(buf, 1sizeof(buf), fd);
        fclose(fd);
        if (len > 0)
        {
            buf[len] = '\0';
            if(dev->type == 2) {         
                seek = strstr(buf, dev->devfile_parts[0]);
                if (seek != NULL)
                {
                    return KK_FS_OK;/*have one part mounted return 1*/
                }
                }

        }
    }
    else
    {
        perror(FILE_MOUNT_CHECK);
    }
    return KK_FS_FAIL;
}

static int check_attach(SCSI_USB_DEV * dev)
{//检测设备是否连接
//linux中只要设备被插入过就会记住该设备
//只能通过Attached来判断是否连接
       char buf[512];
       int fd;
       int len;
       char * seek;  
       fd = open(dev->file_statu, O_RDONLY);
       if( fd > 0 )
       {
              len = read(fd, buf, sizeof(buf));
              close(fd);
              if ( len > 0 )
              {
                     seek = strstr(buf, "Attached:");
                     if (seek)
                     {
                            seek += strlen( "Attached:");
                            while(*seek == ' ') seek++;
                            return *seek=='Y';
                     }
              }
       }
       else
       {
              perror(dev->file_statu);
       }
       return 0;
}
//mount format: # mount -t vfat /dev/sda1 /1 
/*

* # cat /proc/mounts 
* rootfs / rootfs rw 0 0
* proc /proc proc rw 0 0
* devpts /dev/pts devpts rw,mode=600 0 0
* sysfs /sys sysfs rw 0 0
* /dev/mtdblock3 /usr/sbin/zoran squashfs ro 0 0
* /dev/sda1 /tmp/usbdisk/disk0/part0 vfat rw,fmask=0022,dmask=0022,codepage=cp437,iocharset=iso8859-1 0 0
* /dev/sdb1 /tmp/usbdisk/disk0/part0 vfat rw,fmask=0022,dmask=0022,codepage=cp437,iocharset=iso8859-1 0 0
* /dev/sdc1 /tmp/usbdisk/disk0/part0 vfat rw,fmask=0022,dmask=0022,codepage=cp437,iocharset=iso8859-1 0 0
*/
static int do_mount(SCSI_USB_DEV *dev)
{
    int i              = 0;
    int is_vcd         = 0;
    int mount_ok       = 0;
    char fstype[10]     = {0};
    char tmpdir[50]     = {0};
    char check_cmd[50] = {0};
    char mount_data[30] = {0};
    char mount_cmd[64] = {0};
    unsigned long mountflags = 0;

    /*
    * CD-ROM这里可以不去考虑,不论其完善与否,可以作为扩展放在这里
    
*/
    if(dev->type == 1 && is_manual_umount == 0)
    {
      
    }
    else if (dev->type == 2)
    {
        sprintf(tmpdir, USB_DISK_MP"/disk%d", dev->index);
        mkdir(tmpdir, 0777);
        strcpy(fstype, "vfat");
        mountflags= 0xc0ed0000;
        strcpy(mount_data,"codepage=936,iocharset=gb2312");
     
       
            mkdir(dev->mount_path[0], 0777);
            sprintf(mount_cmd, "mount -t vfat %s %s", dev->devfile_parts[0], dev->mount_path[0]);
            system(mount_cmd);


    }
    else
    {
        return KK_FS_FAIL;
    }
    return KK_FS_OK;
}

static int do_umount(SCSI_USB_DEV *dev)
{
    int i = 0;
    char tmpdir[50] = {0};
    char mount_cmd[40];
    if (dev->type == 1)//cdrom
    {
  
    }
    else if(dev->type == 2)//usb-storage
    {
         sprintf(mount_cmd,"umount -l %s",dev->mount_path[0]);
         printf("%s\n",mount_cmd);
         i= system(mount_cmd);   
         remove(dev->mount_path[0]);
        
    }
    sprintf(tmpdir, USB_DISK_MP"/disk%d", dev->index);
    remove(tmpdir);
    return KK_FS_OK;
}


static int process_dev(SCSI_USB_DEV * dev)
{
      if( check_attach(dev)){
            if (check_mount(dev) == KK_FS_FAIL)//检测设备是否mount上
            {
               do_mount(dev);
            //printf(" check_mountKK_FS_FAIL \n");
               }
    //  else
          
//printf("check_mount KK_FS_OK \n");
       }      
    else
    {
         if (check_mount(dev) == KK_FS_OK){
              printf("icheck_mount  unmount \n");
             do_umount(dev);
             }
    }    
 
    return KK_FS_OK;
}

int usb_main()
{     
      SCSI_USB_DEV *cur_dev = NULL;
    mkdir(USB_DISK_MP, 0777);
    mkdir(USB_CDROM_MP, 0777);

    while(1)
    {
        find_device();//查找设备 初始化设备列表        
        cur_dev = f_first_dev;
        while(cur_dev)
        {
            process_dev(cur_dev);//对每个设备进行处理
            cur_dev = cur_dev->next_dev;
        }
        sleep(3);   // 3秒钟检测一次        
    }
}

 

要注意的一个地方是: sprintf(mount_cmd,"umount -l %s",dev->mount_path[0]);

加个-l   好用!!!如果你的系统中加入了samba,没有-l会出现:device is busy错误!

posted on 2011-12-06 16:37  Sankye  阅读(1028)  评论(1编辑  收藏  举报