diff --git a/sbin/devd/devd.8 b/sbin/devd/devd.8 index e8fecfeeb99f..97cc104a47a0 100644 --- a/sbin/devd/devd.8 +++ b/sbin/devd/devd.8 @@ -109,6 +109,11 @@ wish to hook into the .Nm system without modifying the user's other config files. +.Pp +All messages that +.Nm +receives are forwarded to the unix domain socket at +.Pa /var/run/devd.pipe . .Sh SEE ALSO .Xr devctl 4 , .Xr devd.conf 5 diff --git a/sbin/devd/devd.cc b/sbin/devd/devd.cc index 71a0f29aa6cc..75b22c3f2329 100644 --- a/sbin/devd/devd.cc +++ b/sbin/devd/devd.cc @@ -30,15 +30,18 @@ // TODO list: // o devd.conf and devd man pages need a lot of help: -// - devd.conf needs to lose the warning about zone files. +// - devd needs to document the unix domain socket // - devd.conf needs more details on the supported statements. #include __FBSDID("$FreeBSD$"); #include -#include +#include +#include #include +#include +#include #include #include @@ -54,11 +57,13 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include "devd.h" /* C compatible definitions */ #include "devd.hh" /* C++ class definitions */ +#define PIPE "/var/run/devd.pipe" #define CF "/etc/devd.conf" #define SYSCTL "hw.bus.devctl_disable" @@ -585,6 +590,56 @@ process_event(char *buffer) cfg.pop_var_table(); } +int +create_socket(const char *name) +{ + int fd, slen; + struct sockaddr_un sun; + + if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) + err(1, "socket"); + bzero(&sun, sizeof(sun)); + sun.sun_family = AF_UNIX; + strlcpy(sun.sun_path, name, sizeof(sun.sun_path)); + slen = SUN_LEN(&sun); + unlink(name); + if (bind(fd, (struct sockaddr *) & sun, slen) < 0) + err(1, "bind"); + listen(fd, 4); + fchown(fd, 0, 0); /* XXX - root.wheel */ + fchmod(fd, 0660); + return (fd); +} + +list clients; + +void +notify_clients(const char *data, int len) +{ + list bad; + list::const_iterator i; + + for (i = clients.begin(); i != clients.end(); i++) { + if (write(*i, data, len) <= 0) { + bad.push_back(*i); + close(*i); + } + } + + for (i = bad.begin(); i != bad.end(); i++) + clients.erase(find(clients.begin(), clients.end(), *i)); +} + +void +new_client(int fd) +{ + int s; + + s = accept(fd, NULL, NULL); + if (s != -1) + clients.push_back(s); +} + static void event_loop(void) { @@ -592,14 +647,17 @@ event_loop(void) int fd; char buffer[DEVCTL_MAXBUF]; int once = 0; + int server_fd, max_fd; timeval tv; fd_set fds; fd = open(PATH_DEVCTL, O_RDONLY); if (fd == -1) - err(1, "Can't open devctl"); + err(1, "Can't open devctl device %s", PATH_DEVCTL); if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) - err(1, "Can't set close-on-exec flag"); + err(1, "Can't set close-on-exec flag on devctl"); + server_fd = create_socket(PIPE); + max_fd = max(fd, server_fd) + 1; while (1) { if (romeo_must_die) break; @@ -619,19 +677,33 @@ event_loop(void) once++; } } - rv = read(fd, buffer, sizeof(buffer) - 1); - if (rv > 0) { - buffer[rv] = '\0'; - while (buffer[--rv] == '\n') - buffer[rv] = '\0'; - process_event(buffer); - } else if (rv < 0) { - if (errno != EINTR) - break; - } else { - /* EOF */ - break; + FD_ZERO(&fds); + FD_SET(fd, &fds); + FD_SET(server_fd, &fds); + rv = select(max_fd, &fds, NULL, NULL, NULL); + if (rv == -1) { + if (errno == EINTR) + continue; + err(1, "select"); } + if (FD_ISSET(fd, &fds)) { + rv = read(fd, buffer, sizeof(buffer) - 1); + if (rv > 0) { + notify_clients(buffer, rv); + buffer[rv] = '\0'; + while (buffer[--rv] == '\n') + buffer[rv] = '\0'; + process_event(buffer); + } else if (rv < 0) { + if (errno != EINTR) + break; + } else { + /* EOF */ + break; + } + } + if (FD_ISSET(server_fd, &fds)) + new_client(server_fd); } close(fd); }