Ubuntu 1804 Desktop U盘/光驱插入监测及挂载监测
最近做的项目要求在不使用第三方库、不更改系统设置及普通用户权限情况下,实时监控U盘及CD-ROM的插入及挂载情况,现在把内容整理一下。
一. 主要数据结构介绍
本程序共有2个主要的数据结构:
- Netlink操作队列
- 设备队列:新插入设备类型、设备名、挂载目录队列
1. Netlink操作队列
本队列主要用于存储NetLink传来的数据,便于处理进程进行处理,数据结构及相关函数如下:
typedef struct _OperationQueue
{
char operation[20]; //哪种操作
char DeviceName[NAME_MAX]; //设备名
struct _OperationQueue *pNext; //下一节点
} OperationQueue;
//判断操作队列是否为空
bool IsEmpty_OperationQueue(OperationQueue *pOperationQueue)
{
return ((pOperationQueue->pNext == NULL) ? true : false);
}
//向队列中存入数据
int Push_OperationQueue(OperationQueue *pOperationQueue, char *operation, char *DeviceName)
{
pthread_mutex_lock(&OperationQueueLock);
OperationQueue *LastNode = pOperationQueue;
int QueueLen = 0;
while (LastNode->pNext != NULL)
{
LastNode = LastNode->pNext; //找到尾节点
QueueLen++;
}
if (QueueLen >= MAX_QUEUE_SIZE)
{
printf("Queue is full!\n");
pthread_mutex_unlock(&OperationQueueLock);
return -1;
}
LastNode->pNext = (OperationQueue *)malloc(sizeof(OperationQueue));
memset(LastNode->pNext, 0, sizeof(OperationQueue));
LastNode->pNext->pNext = NULL;
strcpy(LastNode->pNext->operation, operation);
strcpy(LastNode->pNext->DeviceName, DeviceName);
pthread_mutex_unlock(&OperationQueueLock);
return 0;
}
//从队列中取出数据
bool Pop_OperationQueue(OperationQueue *pOperationQueue, char *operation, char *DeviceName)
{
pthread_mutex_lock(&OperationQueueLock);
if (pOperationQueue->pNext == NULL)
{
printf("Queue is empty!\n");
pthread_mutex_unlock(&OperationQueueLock);
return false;
}
strcpy(operation, pOperationQueue->pNext->operation);
strcpy(DeviceName, pOperationQueue->pNext->DeviceName);
pOperationQueue->pNext = pOperationQueue->pNext->pNext;
// printf("%s ------- %s\n", operation, DeviceName);
// fflush(stdout);
pthread_mutex_unlock(&OperationQueueLock);
return true;
}
2. 设备队列:新插入设备类型、设备名、挂载目录队列
本队列主要用于存储处理后最终信息,数据结构及相关函数如下:
typedef struct _DeviceLink
{
int type; //设备类型 0: udisk; 1: cdrom
char DeviceName[PATH_MAX + NAME_MAX]; //设备名
char MountPath[PATH_MAX + NAME_MAX]; //挂载路径
struct _DeviceLink *pNext; //下一节点
} DeviceLink;
//输出设备信息
void OutputDeviceLink(DeviceLink *pDeviceLink)
{
pthread_mutex_lock(&DeviceLinkLock);
DeviceLink *CurNode = pDeviceLink->pNext;
while (CurNode != NULL)
{
printf("--------------------------\n");
printf("type: %s\n", ((0 == CurNode->type) ? "udisk" : "cdrom"));
printf("DeviceName: %s\n", CurNode->DeviceName);
printf("MountPath: %s\n", CurNode->MountPath);
fflush(stdout);
CurNode = CurNode->pNext;
}
printf("--------------------------\n\n\n\n");
pthread_mutex_unlock(&DeviceLinkLock);
return;
}
//新增设备
void AddDeviceLink(int type, char *DeviceName, char *MountPath, DeviceLink *pDeviceLink)
{
// printf("-+-+-+-+-+-+-AddDeviceLink-+-+-+-+-+-+-+-\n");
// fflush(stdout);
pthread_mutex_lock(&DeviceLinkLock);
DeviceLink *CurNode = pDeviceLink->pNext;
DeviceLink *LastNode = pDeviceLink;
// 先遍历一圈,看看有没有
while (CurNode != NULL)
{
if (strcmp(DeviceName, CurNode->DeviceName) == 0)
{
// CurNode->type = type;
// // 判断一下挂载目录有没有变化,有变化就更新一下
// if ((MountPath[0] != '\0') && (strcmp(MountPath, CurNode->MountPath) != 0))
// {
// strcpy(MountPath, CurNode->MountPath);
// }
pthread_mutex_unlock(&DeviceLinkLock);
return;
}
CurNode = CurNode->pNext;
}
// 没有就新建一个节点
while (LastNode->pNext != NULL)
{
LastNode = LastNode->pNext; //找到尾节点
}
LastNode->pNext = (DeviceLink *)malloc(sizeof(DeviceLink));
memset(LastNode->pNext, 0, sizeof(DeviceLink));
LastNode->pNext->pNext = NULL;
LastNode->pNext->type = type;
// char temp[PATH_MAX + NAME_MAX] = "/dev/";
// strcat(temp, DeviceName);
// strcpy(LastNode->pNext->DeviceName, temp);
strcpy(LastNode->pNext->DeviceName, DeviceName);
strcpy(LastNode->pNext->MountPath, MountPath);
pthread_mutex_unlock(&DeviceLinkLock);
// OutputDeviceLink(pDeviceLink);
return;
}
//更新设备信息
void UpdateDeviceLink(DeviceLink *pDeviceLink, MountMap *pMountMap, int mapnum)
{
pthread_mutex_lock(&DeviceLinkLock);
DeviceLink *CurpDeviceLinkNode = pDeviceLink->pNext;
// 先遍历一圈pDeviceLink
while (CurpDeviceLinkNode != NULL)
{
bool found = false;
for(int i=0; i<mapnum; i++)
{
if (0 == strcmp(CurpDeviceLinkNode->DeviceName, pMountMap[i].DeviceName)) //判断当前设备是否在挂载列表中
{
found = true;
strcpy(CurpDeviceLinkNode->MountPath, pMountMap[i].MountPath);
break;
}
}
if (false == found)
{
strcpy(CurpDeviceLinkNode->MountPath, "");
}
CurpDeviceLinkNode = CurpDeviceLinkNode->pNext;
}
pthread_mutex_unlock(&DeviceLinkLock);
return;
}
//删除设备信息
void DeleteDeviceLink(char *DeviceName, DeviceLink *pDeviceLink)
{
// printf("-+-+-+-+-+-+-DeleteDeviceLink-+-+-+-+-+-+-+-\n");
// printf("Delete %s\n", DeviceName);
// fflush(stdout);
pthread_mutex_lock(&DeviceLinkLock);
DeviceLink *CurNode = pDeviceLink->pNext;
DeviceLink *PreNode = pDeviceLink;
while (CurNode != NULL)
{
if (strcmp(DeviceName, CurNode->DeviceName) == 0)
{
PreNode->pNext = CurNode->pNext;
free(CurNode);
CurNode = NULL;
pthread_mutex_unlock(&DeviceLinkLock);
return;
}
else
{
PreNode = CurNode;
CurNode = CurNode->pNext;
}
}
pthread_mutex_unlock(&DeviceLinkLock);
return;
}
二. 进程介绍
本程序共4个进程:
- USB插入监测进程:从NetLink得到操作及设备名,存入Netlink操作队列中
- 解析操作数据进程:从Netlink操作队列中取出数据,处理后存入设备队列中
- 获取挂载信息进程:通过循环遍历系统挂载文件判断设备队列中设备挂载情况
- 主进程:休眠并定时打印出新插入的设备是U盘或光驱、打印出U盘/光驱名及挂载情况
1. USB插入监测进程
由于考虑到权限及不更改系统设置情况,udev就无法使用,经过网上检索,发现了NetLink监测USB插入。
Netlink是linux提供的用于内核和用户态进程之间的通信方式,这里就不展开介绍,通过socket与内核进行通信,得到USB设备插入、拔出等信息。
在网上找了一些NetLink的代码demo,进行了简单修改,直接把应用层接收到的NetLink信息打印出来,代码如下:
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/socket.h>
#define MAX_PAYLOAD 1024 /* maximum payload size*/
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd;
struct msghdr msg;
int main(int argc, char *argv[])
{
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd;
struct msghdr msg;
sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
memset(&msg, 0, sizeof(msg));
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid(); /* self pid */
// src_addr.nl_groups = 0; /* not in mcast groups */
src_addr.nl_groups = 1; /* receive broadcast message*/
bind(sock_fd, (struct sockaddr *)&src_addr, sizeof(src_addr));
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0; /* For Linux Kernel */
dest_addr.nl_groups = 0; /* unicast */
nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
/* Fill the netlink message header */
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
nlh->nlmsg_pid = getpid(); /* self pid */
nlh->nlmsg_flags = 0;
/* Fill in the netlink message payload */
// strcpy(NLMSG_DATA(nlh), "Hello you!");
iov.iov_base = (void *)nlh;
iov.iov_len = nlh->nlmsg_len;
msg.msg_name = (void *)&dest_addr;
msg.msg_namelen = sizeof(dest_addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
while (1)
{
memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
// printf(" Waiting message. ...\n");
recvmsg(sock_fd, &msg, 0); //接收内核的消息
printf("%s\n", nlh);
fflush(stdout);
}
close(sock_fd);
}
使用gcc编译,后运行,结果如下:
发现NetLink发送的事件共有以下5种:add、bind、change、remove、unbind,而结合我们的设备名(U盘:sdb,sdb1,光驱:sr0),我们发现只有以下3种可以用到:
- add:插入
- change:更改
- remove:移除
确定操作之后,要截取对应的设备名,将操作和设备名成对存入Netlink操作队列,截取部分代码如下所示:
char operation[20] = {0};
strncpy(operation, (char *)nlh, 19);
*(strchr(operation, '@')) = '\0';
char DeviceName[NAME_MAX] = {0};
strcpy(DeviceName, strrchr((char *)nlh, '/') + 1);
// printf("%s ------- %s\n", operation, DeviceName);
// fflush(stdout);
Push_OperationQueue(pOperationQueue, operation, DeviceName);
2. 解析操作数据进程
本进程负责当Netlink操作队列不为空时,处理Netlink操作队列中的数据,存入设备队列中,代码如下:
void ResolveOperationProcess(void *arg)
{
OperationQueue *pOperationQueue = ((ResolveOperationProcessParams *)arg)->pOperationQueue;
DeviceLink *pDeviceLink = ((ResolveOperationProcessParams *)arg)->pDeviceLink;
// printf("-------------ResolveOperationProcess-----------------\n");
// printf("pDeviceLink: %x\n", pDeviceLink);
// printf("((ResolveOperationProcessParams *)arg)->pDeviceLink: %x\n", ((ResolveOperationProcessParams *)arg)->pDeviceLink);
// printf("pOperationQueue: %x\n", pOperationQueue);
// printf("((ResolveOperationProcessParams *)arg)->pOperationQueue: %x\n", ((ResolveOperationProcessParams *)arg)->pOperationQueue);
// fflush(stdout);
printf("ResolveOperationProcess ...\n");
char operation[20] = {0};
char DeviceName[NAME_MAX] = {0};
while (1)
{
if (IsEmpty_OperationQueue(pOperationQueue))
{
// printf("-+-+-+-+-+-+-+-+-+-+-+-+-+-\n");
// fflush(stdout);
sleep(2);
continue;
}
// if (!Pop_OperationQueue(pOperationQueue, operation, DeviceName));
// {
// continue;
// }
// printf("-+-+-+-+-+-+-+-+-+-+-+-+-+-\n");
// fflush(stdout);
Pop_OperationQueue(pOperationQueue, operation, DeviceName);
// printf("%s ------- %s\n", operation, DeviceName);
// fflush(stdout);
if (strlen(DeviceName) < 3)
continue;
if ('s' == DeviceName[0] && 'd' == DeviceName[1] && (DeviceName[2] >= 'a' || DeviceName[2] <= 'z')) //sda~sdz, udisk
{
if (0 == strcmp(operation, "add"))
{
AddDeviceLink(0, DeviceName, "", pDeviceLink);
}
else if (0 == strcmp(operation, "remove"))
{
DeleteDeviceLink(DeviceName, pDeviceLink);
}
else if (0 == strcmp(operation, "change"))
{
AddDeviceLink(0, DeviceName, "", pDeviceLink);
}
else
continue;
}
else if ('s' == DeviceName[0] && 'r' == DeviceName[1] && (DeviceName[2] >= '0' || DeviceName[2] <= '9')) //sr0~sr9, cdrom
{
if (0 == strcmp(operation, "add"))
{
AddDeviceLink(1, DeviceName, "", pDeviceLink);
}
else if (0 == strcmp(operation, "remove"))
{
DeleteDeviceLink(DeviceName, pDeviceLink);
}
else if (0 == strcmp(operation, "change"))
{
AddDeviceLink(1, DeviceName, "", pDeviceLink);
}
else
continue;
}
else
continue;
}
return;
}
3. 获取挂载信息进程
Ubuntu 18.04 Desktop中设备挂载情况存储再/proc/mounts
文件中,通过遍历该文件,得到所有挂载对应关系,然后对比设备队列,更新设备队列中的挂载路径。代码如下:
void CheckMountProcess(DeviceLink *pDeviceLink)
{
printf("CheckMountProcess ...\n");
while (1)
{
// 获取行数,用于确定创建对照表的大小
int row = 0;
char cmd[MAX_BUFF_LEN] = {0};
char buffer[MAX_BUFF_LEN] = {0};
FILE *pf;
sprintf(cmd, "cat %s | grep -n \" \" | awk -F \":\" '{print $1}' | tail -n1", FILE_MOUNT_CHECK);
// system(cmd);
pf = popen(cmd, "r");
fread(buffer, sizeof(buffer), 1, pf);
row = atoi(buffer);
pclose(pf);
// printf("ROW: %d\n", row);
char RawData[1024] = {0};
FILE *fp = fopen(FILE_MOUNT_CHECK, "r");
if (NULL == fp)
{
printf("failed to open dos.txt\n");
continue;
}
MountMap *pMountMap = (MountMap *)malloc(sizeof(MountMap) * row);
if (NULL == pMountMap)
{
printf("Malloc failed!\n");
continue;
}
memset(pMountMap, 0, sizeof(MountMap) * row);
int mapnum = 0; // 对照表实际大小
while (!feof(fp))
{
memset(RawData, 0, sizeof(RawData));
fgets(RawData, sizeof(RawData) - 1, fp); // 包含了换行符
// printf("%s", RawData);
if (strlen(RawData) <= 5)
continue;
if ((RawData[0] != '/') || (RawData[1] != 'd') || (RawData[2] != 'e') || (RawData[3] != 'v') || (RawData[4] != '/')) // 不是/dev/开头,直接pass
continue;
char DeviceName[PATH_MAX + NAME_MAX] = {0};
char MountPath[PATH_MAX + NAME_MAX] = {0};
strcpy(DeviceName, RawData + 5); // +5是为了去掉/dev/
*strchr(DeviceName, ' ') = '\0';
strcpy(MountPath, strchr(RawData, ' ') + 1);
*strchr(MountPath, ' ') = '\0';
// printf("DeviceName: %s \t MountPath: %s\n", DeviceName, MountPath);
strcpy(pMountMap[mapnum].DeviceName, DeviceName);
strcpy(pMountMap[mapnum].MountPath, MountPath);
mapnum ++;
}
fclose(fp);
UpdateDeviceLink(pDeviceLink, pMountMap, mapnum);
free(pMountMap);
pMountMap = NULL;
sleep(2); //2秒轮询一次
}
return;
}
4. 主进程
每隔5秒钟,输出一下设备队列。代码如下:
while (1)
{
sleep(5);
OutputDeviceLink(pDeviceLink);
// printf("Sleep .........\n");
fflush(stdout);
}
三. 现象展示
执行gcc UsbMonitor.c -o UsbMonitor -lpthread
编译后运行。结果如下:
光驱现象类似,就不具体展示了。
四. 完整代码
完整代码如下:
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <pthread.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/socket.h>
#include <linux/limits.h>
#define UEVENT_BUFFER_SIZE 2048 /* maximum payload size*/
#define MAX_QUEUE_SIZE 1024 //队列大小
#define MAX_PAYLOAD 1024 /* maximum payload size*/
#define MAX_BUFF_LEN 128 //命令最大字符数
#define FILE_MOUNT_CHECK "/proc/mounts" //用来检测设备是否被mount
static pthread_mutex_t DeviceLinkLock;
static pthread_mutex_t OperationQueueLock;
typedef struct _DeviceLink
{
int type; //设备类型 0: udisk; 1: cdrom
char DeviceName[PATH_MAX + NAME_MAX]; //设备名
char MountPath[PATH_MAX + NAME_MAX]; //挂载路径
struct _DeviceLink *pNext; //下一节点
} DeviceLink;
typedef struct _OperationQueue
{
char operation[20]; //哪种操作
char DeviceName[NAME_MAX]; //设备名
struct _OperationQueue *pNext; //下一节点
} OperationQueue;
typedef struct _ResolveOperationProcessParams
{
DeviceLink *pDeviceLink;
OperationQueue *pOperationQueue;
} ResolveOperationProcessParams;
typedef struct _MountMap
{
char DeviceName[PATH_MAX + NAME_MAX];
char MountPath[PATH_MAX + NAME_MAX];
} MountMap;
//判断操作队列是否为空
bool IsEmpty_OperationQueue(OperationQueue *pOperationQueue)
{
return ((pOperationQueue->pNext == NULL) ? true : false);
}
//向队列中存入数据
int Push_OperationQueue(OperationQueue *pOperationQueue, char *operation, char *DeviceName)
{
pthread_mutex_lock(&OperationQueueLock);
OperationQueue *LastNode = pOperationQueue;
int QueueLen = 0;
while (LastNode->pNext != NULL)
{
LastNode = LastNode->pNext; //找到尾节点
QueueLen++;
}
if (QueueLen >= MAX_QUEUE_SIZE)
{
printf("Queue is full!\n");
pthread_mutex_unlock(&OperationQueueLock);
return -1;
}
LastNode->pNext = (OperationQueue *)malloc(sizeof(OperationQueue));
memset(LastNode->pNext, 0, sizeof(OperationQueue));
LastNode->pNext->pNext = NULL;
strcpy(LastNode->pNext->operation, operation);
strcpy(LastNode->pNext->DeviceName, DeviceName);
pthread_mutex_unlock(&OperationQueueLock);
return 0;
}
//从队列中取出数据
bool Pop_OperationQueue(OperationQueue *pOperationQueue, char *operation, char *DeviceName)
{
pthread_mutex_lock(&OperationQueueLock);
if (pOperationQueue->pNext == NULL)
{
printf("Queue is empty!\n");
pthread_mutex_unlock(&OperationQueueLock);
return false;
}
strcpy(operation, pOperationQueue->pNext->operation);
strcpy(DeviceName, pOperationQueue->pNext->DeviceName);
pOperationQueue->pNext = pOperationQueue->pNext->pNext;
// printf("%s ------- %s\n", operation, DeviceName);
// fflush(stdout);
pthread_mutex_unlock(&OperationQueueLock);
return true;
}
//输出设备信息
void OutputDeviceLink(DeviceLink *pDeviceLink)
{
pthread_mutex_lock(&DeviceLinkLock);
DeviceLink *CurNode = pDeviceLink->pNext;
while (CurNode != NULL)
{
printf("--------------------------\n");
printf("type: %s\n", ((0 == CurNode->type) ? "udisk" : "cdrom"));
printf("DeviceName: %s\n", CurNode->DeviceName);
printf("MountPath: %s\n", CurNode->MountPath);
fflush(stdout);
CurNode = CurNode->pNext;
}
printf("--------------------------\n\n\n\n");
pthread_mutex_unlock(&DeviceLinkLock);
return;
}
//新增设备
void AddDeviceLink(int type, char *DeviceName, char *MountPath, DeviceLink *pDeviceLink)
{
// printf("-+-+-+-+-+-+-AddDeviceLink-+-+-+-+-+-+-+-\n");
// fflush(stdout);
pthread_mutex_lock(&DeviceLinkLock);
DeviceLink *CurNode = pDeviceLink->pNext;
DeviceLink *LastNode = pDeviceLink;
// 先遍历一圈,看看有没有
while (CurNode != NULL)
{
if (strcmp(DeviceName, CurNode->DeviceName) == 0)
{
// CurNode->type = type;
// // 判断一下挂载目录有没有变化,有变化就更新一下
// if ((MountPath[0] != '\0') && (strcmp(MountPath, CurNode->MountPath) != 0))
// {
// strcpy(MountPath, CurNode->MountPath);
// }
pthread_mutex_unlock(&DeviceLinkLock);
return;
}
CurNode = CurNode->pNext;
}
// 没有就新建一个节点
while (LastNode->pNext != NULL)
{
LastNode = LastNode->pNext; //找到尾节点
}
LastNode->pNext = (DeviceLink *)malloc(sizeof(DeviceLink));
memset(LastNode->pNext, 0, sizeof(DeviceLink));
LastNode->pNext->pNext = NULL;
LastNode->pNext->type = type;
// char temp[PATH_MAX + NAME_MAX] = "/dev/";
// strcat(temp, DeviceName);
// strcpy(LastNode->pNext->DeviceName, temp);
strcpy(LastNode->pNext->DeviceName, DeviceName);
strcpy(LastNode->pNext->MountPath, MountPath);
pthread_mutex_unlock(&DeviceLinkLock);
// OutputDeviceLink(pDeviceLink);
return;
}
//更新设备信息
void UpdateDeviceLink(DeviceLink *pDeviceLink, MountMap *pMountMap, int mapnum)
{
pthread_mutex_lock(&DeviceLinkLock);
DeviceLink *CurpDeviceLinkNode = pDeviceLink->pNext;
// 先遍历一圈pDeviceLink
while (CurpDeviceLinkNode != NULL)
{
bool found = false;
for(int i=0; i<mapnum; i++)
{
if (0 == strcmp(CurpDeviceLinkNode->DeviceName, pMountMap[i].DeviceName)) //判断当前设备是否在挂载列表中
{
found = true;
strcpy(CurpDeviceLinkNode->MountPath, pMountMap[i].MountPath);
break;
}
}
if (false == found)
{
strcpy(CurpDeviceLinkNode->MountPath, "");
}
CurpDeviceLinkNode = CurpDeviceLinkNode->pNext;
}
pthread_mutex_unlock(&DeviceLinkLock);
return;
}
//删除设备信息
void DeleteDeviceLink(char *DeviceName, DeviceLink *pDeviceLink)
{
// printf("-+-+-+-+-+-+-DeleteDeviceLink-+-+-+-+-+-+-+-\n");
// printf("Delete %s\n", DeviceName);
// fflush(stdout);
pthread_mutex_lock(&DeviceLinkLock);
DeviceLink *CurNode = pDeviceLink->pNext;
DeviceLink *PreNode = pDeviceLink;
while (CurNode != NULL)
{
if (strcmp(DeviceName, CurNode->DeviceName) == 0)
{
PreNode->pNext = CurNode->pNext;
free(CurNode);
CurNode = NULL;
pthread_mutex_unlock(&DeviceLinkLock);
return;
}
else
{
PreNode = CurNode;
CurNode = CurNode->pNext;
}
}
pthread_mutex_unlock(&DeviceLinkLock);
return;
}
void NetLinkProcess(OperationQueue *pOperationQueue)
{
printf("NetLinkProcess ...\n");
// printf("-------------NetLinkProcess-----------------\n");
// printf("pOperationQueue: %x\n", pOperationQueue);
// fflush(stdout);
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd;
struct msghdr msg;
sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
memset(&msg, 0, sizeof(msg));
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid(); /* self pid */
// src_addr.nl_groups = 0; /* not in mcast groups */
src_addr.nl_groups = 1; /* receive broadcast message*/
bind(sock_fd, (struct sockaddr *)&src_addr, sizeof(src_addr));
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0; /* For Linux Kernel */
dest_addr.nl_groups = 0; /* unicast */
nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
/* Fill the netlink message header */
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
nlh->nlmsg_pid = getpid(); /* self pid */
nlh->nlmsg_flags = 0;
/* Fill in the netlink message payload */
// strcpy(NLMSG_DATA(nlh), "Hello you!");
iov.iov_base = (void *)nlh;
iov.iov_len = nlh->nlmsg_len;
msg.msg_name = (void *)&dest_addr;
msg.msg_namelen = sizeof(dest_addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
while (1)
{
memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
// printf(" Waiting message. ...\n");
recvmsg(sock_fd, &msg, 0); //接收内核的消息
char operation[20] = {0};
strncpy(operation, (char *)nlh, 19);
*(strchr(operation, '@')) = '\0';
char DeviceName[NAME_MAX] = {0};
strcpy(DeviceName, strrchr((char *)nlh, '/') + 1);
// printf("%s ------- %s\n", operation, DeviceName);
// fflush(stdout);
Push_OperationQueue(pOperationQueue, operation, DeviceName);
}
close(sock_fd);
}
void ResolveOperationProcess(void *arg)
{
OperationQueue *pOperationQueue = ((ResolveOperationProcessParams *)arg)->pOperationQueue;
DeviceLink *pDeviceLink = ((ResolveOperationProcessParams *)arg)->pDeviceLink;
// printf("-------------ResolveOperationProcess-----------------\n");
// printf("pDeviceLink: %x\n", pDeviceLink);
// printf("((ResolveOperationProcessParams *)arg)->pDeviceLink: %x\n", ((ResolveOperationProcessParams *)arg)->pDeviceLink);
// printf("pOperationQueue: %x\n", pOperationQueue);
// printf("((ResolveOperationProcessParams *)arg)->pOperationQueue: %x\n", ((ResolveOperationProcessParams *)arg)->pOperationQueue);
// fflush(stdout);
printf("ResolveOperationProcess ...\n");
char operation[20] = {0};
char DeviceName[NAME_MAX] = {0};
while (1)
{
if (IsEmpty_OperationQueue(pOperationQueue))
{
// printf("-+-+-+-+-+-+-+-+-+-+-+-+-+-\n");
// fflush(stdout);
sleep(2);
continue;
}
// if (!Pop_OperationQueue(pOperationQueue, operation, DeviceName));
// {
// continue;
// }
// printf("-+-+-+-+-+-+-+-+-+-+-+-+-+-\n");
// fflush(stdout);
Pop_OperationQueue(pOperationQueue, operation, DeviceName);
// printf("%s ------- %s\n", operation, DeviceName);
// fflush(stdout);
if (strlen(DeviceName) < 3)
continue;
if ('s' == DeviceName[0] && 'd' == DeviceName[1] && (DeviceName[2] >= 'a' || DeviceName[2] <= 'z')) //sda~sdz, udisk
{
if (0 == strcmp(operation, "add"))
{
AddDeviceLink(0, DeviceName, "", pDeviceLink);
}
else if (0 == strcmp(operation, "remove"))
{
DeleteDeviceLink(DeviceName, pDeviceLink);
}
else if (0 == strcmp(operation, "change"))
{
AddDeviceLink(0, DeviceName, "", pDeviceLink);
}
else
continue;
}
else if ('s' == DeviceName[0] && 'r' == DeviceName[1] && (DeviceName[2] >= '0' || DeviceName[2] <= '9')) //sr0~sr9, cdrom
{
if (0 == strcmp(operation, "add"))
{
AddDeviceLink(1, DeviceName, "", pDeviceLink);
}
else if (0 == strcmp(operation, "remove"))
{
DeleteDeviceLink(DeviceName, pDeviceLink);
}
else if (0 == strcmp(operation, "change"))
{
AddDeviceLink(1, DeviceName, "", pDeviceLink);
}
else
continue;
}
else
continue;
}
return;
}
void CheckMountProcess(DeviceLink *pDeviceLink)
{
printf("CheckMountProcess ...\n");
while (1)
{
// 获取行数,用于确定创建对照表的大小
int row = 0;
char cmd[MAX_BUFF_LEN] = {0};
char buffer[MAX_BUFF_LEN] = {0};
FILE *pf;
sprintf(cmd, "cat %s | grep -n \" \" | awk -F \":\" '{print $1}' | tail -n1", FILE_MOUNT_CHECK);
// system(cmd);
pf = popen(cmd, "r");
fread(buffer, sizeof(buffer), 1, pf);
row = atoi(buffer);
pclose(pf);
// printf("ROW: %d\n", row);
char RawData[1024] = {0};
FILE *fp = fopen(FILE_MOUNT_CHECK, "r");
if (NULL == fp)
{
printf("failed to open dos.txt\n");
continue;
}
MountMap *pMountMap = (MountMap *)malloc(sizeof(MountMap) * row);
if (NULL == pMountMap)
{
printf("Malloc failed!\n");
continue;
}
memset(pMountMap, 0, sizeof(MountMap) * row);
int mapnum = 0; // 对照表实际大小
while (!feof(fp))
{
memset(RawData, 0, sizeof(RawData));
fgets(RawData, sizeof(RawData) - 1, fp); // 包含了换行符
// printf("%s", RawData);
if (strlen(RawData) <= 5)
continue;
if ((RawData[0] != '/') || (RawData[1] != 'd') || (RawData[2] != 'e') || (RawData[3] != 'v') || (RawData[4] != '/')) // 不是/dev/开头,直接pass
continue;
char DeviceName[PATH_MAX + NAME_MAX] = {0};
char MountPath[PATH_MAX + NAME_MAX] = {0};
strcpy(DeviceName, RawData + 5); // +5是为了去掉/dev/
*strchr(DeviceName, ' ') = '\0';
strcpy(MountPath, strchr(RawData, ' ') + 1);
*strchr(MountPath, ' ') = '\0';
// printf("DeviceName: %s \t MountPath: %s\n", DeviceName, MountPath);
strcpy(pMountMap[mapnum].DeviceName, DeviceName);
strcpy(pMountMap[mapnum].MountPath, MountPath);
mapnum ++;
}
fclose(fp);
UpdateDeviceLink(pDeviceLink, pMountMap, mapnum);
free(pMountMap);
pMountMap = NULL;
sleep(2); //2秒轮询一次
}
return;
}
int main(int argc, char *argv[])
{
pthread_mutex_init(&DeviceLinkLock, NULL);
pthread_mutex_init(&OperationQueueLock, NULL);
DeviceLink *pDeviceLink = (DeviceLink *)malloc(sizeof(DeviceLink)); // 设备详情链表
if (NULL == pDeviceLink)
{
printf("Malloc failed\n");
exit(-3);
}
pDeviceLink->pNext = NULL;
OperationQueue *pOperationQueue = (OperationQueue *)malloc(sizeof(OperationQueue)); //Netlink操作队列
if (NULL == pOperationQueue)
{
printf("Malloc failed\n");
exit(-3);
}
pOperationQueue->pNext = NULL;
int res;
pthread_t tid_NetLink;
res = pthread_create(&tid_NetLink, NULL, (void *)NetLinkProcess, (void *)pOperationQueue);
if (0 != res)
{
printf("pthread_create error.\n");
fflush(stdout);
exit(-1);
}
ResolveOperationProcessParams ropargs = {pDeviceLink, pOperationQueue};
// printf("-------------main-----------------\n");
// printf("pDeviceLink: %x\n", pDeviceLink);
// printf("ropargs.pDeviceLink: %x\n", ropargs.pDeviceLink);
// printf("pOperationQueue: %x\n", pOperationQueue);
// printf("ropargs.pOperationQueue: %x\n", ropargs.pOperationQueue);
// fflush(stdout);
pthread_t tid_OperationQueue;
res = pthread_create(&tid_OperationQueue, NULL, (void *)ResolveOperationProcess, &ropargs);
if (0 != res)
{
printf("pthread_create error.\n");
fflush(stdout);
exit(-1);
}
pthread_t tid_CheckMount;
res = pthread_create(&tid_CheckMount, NULL, (void *)CheckMountProcess, (void *)pDeviceLink);
if (0 != res)
{
printf("pthread_create error.\n");
fflush(stdout);
exit(-1);
}
// res = pthread_join(tid_NetLink, NULL);
// if (0 != res)
// {
// printf("Thread joined error.\n");
// fflush(stdout);
// exit(-2);
// }
// printf("wait .........\n");
while (1)
{
sleep(5);
OutputDeviceLink(pDeviceLink);
// printf("Sleep .........\n");
fflush(stdout);
}
free(pDeviceLink);
pDeviceLink = NULL;
free(pOperationQueue);
pOperationQueue = NULL;
return 0;
}