首页 > 代码库 > linux下u盘检测程序

linux下u盘检测程序

       获得U盘的插入或者拔取得信息的传统方法是在内核级运行hotplug程序,相关参数通过环境变量传递过来,再由hotplug通知其他关注hotplug的应用程序,但是效率比较低.

     网上查找知道:

   用户空间的程序与设备通信的方法,主要有以下几种方式,
  1. 通过ioperm获取操作IO端口的权限,然后用inb/inw/ inl/ outb/outw/outl等函数,避开设备驱动程序,直接去操作IO端口。(没有用过)
  2. 用ioctl函数去操作/dev目录下对应的设备,这是设备驱动程序提供的接口。像键盘、鼠标和触摸屏等输入设备一般都是这样做的。
  3. 用write/read/mmap去操作/dev目录下对应的设备,这也是设备驱动程序提供的接口。像framebuffer等都是这样做的。

       上面的方法在大多数情况下,都可以正常工作,但是对于热插拨(hotplug)的设备,比如像U盘,就有点困难了,因为不知道:什么时候设备插上了,什么时候设备拔掉了。这就是所谓的hotplug问题了。

   新的方法是采用NETLINK实现的,这是一种特殊类型的socket,专门用于内核空间与用户空间的异步通信。


   先说明几个总要的结构体:

  sockaddr_nl结构:
      struct sockaddr_nl {
                       sa_family_t nl_family;    //AF_NETLINK
                       unsigned short nl_pad;    // 0
                       pid_t nl_pid;         // 进程pid
                        u_32 nl_groups;      // 多播组掩码
                   }nl;

  int setsockopt(
                      SOCKET s,
                      int level,
                      int optname,
                      const char* optval,
                      int optlen
                );

s(套接字): 指向一个打开的套接口描述字
          level:(级别): 指定选项代码的类型。
          SOL_SOCKET: 基本套接口
          IPPROTO_IP: IPv4套接口
          IPPROTO_IPV6: IPv6套接口
          IPPROTO_TCP: TCP套接口
          optname(选项名): 选项名称
          optval(选项值): 是一个指向变量的指针 类型:整形,套接口结构, 其他结构类型:linger{}, timeval{ }
          optlen(选项长度) :optval 的
大小

贴出代码:

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <linux/netlink.h>
#include <dirent.h>
#include <sys/statfs.h>

int init_socket()
{
	struct sockaddr_nl snl;
	const int BufferSize= 1024;
	int retval;
	
	memset(&snl,0,sizeof(struct sockaddr_nl));
	snl.nl_family = AF_NETLINK;
	snl.nl_pid = getpid();
	snl.nl_groups = 1;
	
	int Sock_id = socket(PF_NETLINK,SOCK_DGRAM,NETLINK_KOBJECT_UEVENT);
	
	if(Sock_id == -1)
	printf("sock err:%m\n"),exit(-1);
	
	// set reveive buffer
	setsockopt(Sock_id,SOL_SOCKET,SO_RCVBUFFORCE,&BufferSize,sizeof(BufferSize));
	retval = bind(Sock_id,(struct sockaddr*)&snl,sizeof(struct sockaddr_nl));
	if(retval==-1)
	printf("bind err:%m\n"),close(Sock_id),exit(-1);
	return Sock_id;
}

// 该函数主要作用时检测u盘的 总空间,剩余空间,剩余空间百分比
double GetDiskFreeSpacePercent(const char *pDisk,double* freespace,double*  totalspace)
{
	struct statfs disk_statfs;
	double freeSpacePercent =0;
	if(statfs(pDisk,&disk_statfs) == 0)
	{
		
		*freespace = (disk_statfs.f_bsize * disk_statfs.f_bfree) / (1024*1024*1024.0);
		*totalspace = (disk_statfs.f_bsize * disk_statfs.f_blocks) / (1024*1024*1024.0);
	}
	return freeSpacePercent = (*freespace)/(*totalspace)*100;

}

#define BUFFER_SIZE 2048

int main()
{
	DIR *dp;
	double f=0;
	double t=0;
	double percent=0;
	const char* path="/media/cjl/disk";
	int sd= init_socket();
	while(1)
	{
		char buf[BUFFER_SIZE] = {0};
		recv(sd,&buf,sizeof(buf),0);
		//printf("%s\n",buf);
			if(!memcmp(buf,"add@",4) /*&& !memcmp(&buf[strlen(buf) - 4],"/sdb",4)*/)
		{
			printf("Found U Disk\n");
			break;
		}
	}
	printf("是否打开u盘Y/N\n");
	char c;
	scanf("%c",&c);
	if(c=='Y' || c=='y')
	{
		if((dp = opendir(path)) ==NULL)
		{
			printf("打开失败!\n");
		}
		else
		{
			system("ls -l /media/cjl/disk");
		}
	}
	else if(c=='N' || c=='n')
	
	percent = GetDiskFreeSpacePercent(path,&f,&t);
	
	printf("u盘剩余空间: %.2f\n",f);
	printf("u盘总空间:   %.2f\n",t);
	printf("u盘剩余空间百分比: %0.2f%%\n",percent);
	return 0;
}


                 









linux下u盘检测程序