1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
#include "../include/Hotplug.hpp"
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/types.h>
#include <linux/netlink.h>
namespace gsr {
Hotplug::~Hotplug() {
if(fd > 0)
close(fd);
}
bool Hotplug::start() {
if(started)
return false;
struct sockaddr_nl nls = {
AF_NETLINK,
0,
(unsigned int)getpid(),
(unsigned int)-1
};
fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if(fd == -1)
return false; /* Not root user */
if(bind(fd, (const struct sockaddr*)&nls, sizeof(struct sockaddr_nl))) {
close(fd);
fd = -1;
return false;
}
started = true;
return true;
}
int Hotplug::steal_fd() {
const int val = fd;
fd = -1;
return val;
}
void Hotplug::process_event_data(int fd, const HotplugEventCallback &callback) {
const int bytes_read = read(fd, event_data, sizeof(event_data));
if(bytes_read <= 0)
return;
/* Hotplug data ends with a newline and a null terminator */
int data_index = 0;
while(data_index < bytes_read) {
parse_netlink_data(event_data + data_index, callback);
data_index += strlen(event_data + data_index) + 1; /* Skip null terminator as well */
}
}
/* TODO: This assumes SUBSYSTEM= is output before DEVNAME=, is that always true? */
void Hotplug::parse_netlink_data(const char *line, const HotplugEventCallback &callback) {
const char *at_symbol = strchr(line, '@');
if(at_symbol) {
event_is_add = strncmp(line, "add@", 4) == 0;
event_is_remove = strncmp(line, "remove@", 7) == 0;
subsystem_is_input = false;
} else if(event_is_add || event_is_remove) {
if(strcmp(line, "SUBSYSTEM=input") == 0)
subsystem_is_input = true;
if(subsystem_is_input && strncmp(line, "DEVNAME=", 8) == 0) {
if(event_is_add)
callback(HotplugAction::ADD, line+8);
else if(event_is_remove)
callback(HotplugAction::REMOVE, line+8);
event_is_add = false;
event_is_remove = false;
}
}
}
}
|