Index: sbin/devd/devd.cc =================================================================== --- sbin/devd/devd.cc +++ sbin/devd/devd.cc @@ -99,6 +99,7 @@ #include #include #include +#include #include "devd.h" /* C compatible definitions */ #include "devd.hh" /* C++ class definitions */ @@ -146,6 +147,8 @@ static const char attach = '+'; static const char detach = '-'; +static const char enumerate = '%'; + static struct pidfh *pfh; static int no_daemon = 0; @@ -157,6 +160,9 @@ static const char *configfile = CF; +// Store device attach lines (indexed by system) for enumeration +static unordered_map> current_devs; + static void devdlog(int priority, const char* message, ...) __printflike(2, 3); static void event_loop(void); @@ -841,6 +847,7 @@ char *sp; struct timeval tv; char *timestr; + char *orig_buffer = strdup(buffer); sp = buffer + 1; devdlog(LOG_INFO, "Processing event '%s'\n", buffer); @@ -860,10 +867,30 @@ // Match doesn't have a device, and the format is a little // different, so handle it separately. + string sys, typ; switch (type) { case notify: //! (k=v)* sp = cfg.set_vars(sp); + // Manage the enumeration map + sys = cfg.get_variable("system"); + typ = cfg.get_variable("type"); + if (typ == "ATTACH" || typ == "CREATE") { + current_devs[sys].push_back(orig_buffer); + } else if (typ == "DETACH" || typ == "DESTROY") { + string attach_line(orig_buffer); + string::size_type pos = attach_line.find("DETACH"); + if (pos != string::npos) { + attach_line.replace(pos, string("DETACH").size(), "ATTACH"); + } + for (vector::iterator it = current_devs[sys].begin(); it != current_devs[sys].end();) { + if (*it == attach_line) { + it = current_devs[sys].erase(it); // returns a valid iterator to the next item + } else { + it++; + } + } + } break; case nomatch: //? at location pnp-info on bus @@ -1001,9 +1028,7 @@ int sndbuf_size; /* - * First go reap any zombie clients, then accept the connection, and - * shut down the read side to stop clients from consuming kernel memory - * by sending large buffers full of data we'll never read. + * First go reap any zombie clients, then accept the connection. */ check_clients(); s.socktype = socktype; @@ -1013,13 +1038,32 @@ if (setsockopt(s.fd, SOL_SOCKET, SO_SNDBUF, &sndbuf_size, sizeof(sndbuf_size))) err(1, "setsockopt"); - shutdown(s.fd, SHUT_RD); clients.push_back(s); ++num_clients; } else err(1, "accept"); } +static void +process_client_request(int fd) +{ + char buffer[128] = { 0 }; + + if (read(fd, buffer, sizeof(buffer) - 1) < 0) { + return; + } + + if (buffer[0] == enumerate) { + string key(&buffer[1]); + key.erase(std::remove(key.begin(), key.end(), '\n'), key.end()); + for (vector::iterator it = current_devs[key].begin(); it != current_devs[key].end(); it++) { + send(fd, it->c_str(), it->size(), 0); + send(fd, "\n", 1, 0); + } + send(fd, "%\n", 2, 0); + } +} + static void event_loop(void) { @@ -1086,6 +1130,11 @@ tv.tv_sec = 2; tv.tv_usec = 0; } + max_fd = max(fd, max(stream_fd, seqpacket_fd)) + 1; + for (list::iterator it = clients.begin(); it != clients.end(); it++) { + FD_SET(it->fd, &fds); + max_fd += it->fd; + } rv = select(max_fd, &fds, NULL, NULL, &tv); if (got_siginfo) { devdlog(LOG_NOTICE, "Events received so far=%u\n", @@ -1134,6 +1183,12 @@ */ if (FD_ISSET(seqpacket_fd, &fds)) new_client(seqpacket_fd, SOCK_SEQPACKET); + for (list::iterator it = clients.begin(); it != clients.end(); it++) { + if (FD_ISSET(it->fd, &fds)) { + devdlog(LOG_WARNING, "Client request from fd %d\n", it->fd); + process_client_request(it->fd); + } + } } cfg.remove_pidfile(); close(seqpacket_fd);