I am working on a C++ application for embedded devices that listens to USB hotplug events via a netlink socket. Detecting events works flawlessly but additionally I would like to query already attached devices in the beginning of the program. I was able to archive the same functionality for network interfaces but it seems that USB is a pretty different story. So my questions are:
- Is it even possible to list already attached USB devices using a netlink socket?
- If it is possible, how would a request message look like?
- If it is not possible, what would be a good alternative with little dependencies?
MWE for receiving hotplug events:
#include <sys/signalfd.h>
#include <csignal>
#include <linux/netlink.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstring>
#include <cerrno>
#include <cstdlib>
#include <cstdio>
#include <poll.h>
int main() {
struct sockaddr_nl addr = {0};
char buffer[4096];
sigset_t signal_set;
struct signalfd_siginfo signal_info;
struct pollfd pfd[2];
int ret_poll;
ssize_t n;
// Set signals we want to catch
sigemptyset(&signal_set);
sigaddset(&signal_set, SIGTERM);
sigaddset(&signal_set, SIGINT);
// Change the signal mask and check
if (sigprocmask(SIG_BLOCK, &signal_set, nullptr) < 0) {
fprintf(stderr, "Error while sigprocmask(): %s\n", strerror(errno));
return EXIT_FAILURE;
}
// Get a signal file descriptor
pfd[0].fd = signalfd(-1, &signal_set, 0);
// Check the signal file descriptor
if (pfd[0].fd < 0) {
fprintf(stderr, "Error while signalfd(): %s\n", strerror(errno));
return EXIT_FAILURE;
}
// Create a netlink socket
pfd[1].fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
if (pfd[1].fd < 0) {
fprintf(stderr, "Netlink socket create failed: %s\n", strerror(errno));
return EXIT_FAILURE;
}
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
addr.nl_groups = 2;
if (bind(pfd[1].fd, (struct sockaddr *) &addr, sizeof(addr))) {
fprintf(stderr, "Netlink socket bind() failed: %s\n", strerror(errno));
return EXIT_FAILURE;
}
pfd[0].events = POLLIN;
pfd[1].events = POLLIN;
while (true) {
// Wait for events without time limit
ret_poll = poll(pfd, 2, -1);
if (ret_poll < 0) {
fprintf(stderr, "SystemMaster::execute() -> "
"Error while poll(): %s\n", strerror(errno));
return EXIT_FAILURE;
}
// True, if a signal from the operating system was sent to this process
if (pfd[0].revents & POLLIN) {
// Get the signal
n = read(pfd[0].fd, &signal_info, sizeof(signal_info));
// True, if an error occurred while getting the signal
if (n == -1) {
fprintf(stderr, "Error while read() on signal pipe: %s\n", strerror(errno));
}
// Check, if we are really interested in the caught signal
if ((signal_info.ssi_signo == SIGTERM) || (signal_info.ssi_signo == SIGINT)) {
printf("Signal received\n");
}
break;
}
// True, if a netlink message is available
if (pfd[1].revents & POLLIN) {
n = recv(pfd[1].fd, &buffer, sizeof(buffer), 0);
for (int i = 0; i < n; ++i) {
if (buffer[i] == 0) printf("\n");
else if (buffer[i] > 33 && buffer[i] < 126) printf("%c", buffer[i]);
}
}
}
// Close both file descriptors
close(pfd[0].fd);
close(pfd[1].fd);
return 0;
}
Thanks in advance for any response!