devd(8): Sync with FreeBSD.
authorSascha Wildner <saw@online.de>
Wed, 25 Feb 2015 02:42:41 +0000 (03:42 +0100)
committerSascha Wildner <saw@online.de>
Wed, 25 Feb 2015 02:42:41 +0000 (03:42 +0100)
sbin/devd/devd.8
sbin/devd/devd.cc

index 08a5d04..07bf826 100644 (file)
@@ -23,9 +23,9 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/sbin/devd/devd.8 262914 2014-03-07 23:30:48Z asomers $
+.\" $FreeBSD: head/sbin/devd/devd.8 270004 2014-08-14 22:33:56Z asomers $
 .\"
-.Dd January 30, 2013
+.Dd February 24, 2015
 .Dt DEVD 8
 .Os
 .Sh NAME
@@ -55,9 +55,7 @@ If option
 .Fl f
 is specified more than once, the last file specified is used.
 .It Fl l Ar num
-Limit concurrent
-.Pa /var/run/devd.pipe
-connections to
+Limit concurrent socket connections to
 .Ar num .
 The default connection limit is 10.
 .It Fl n
@@ -130,22 +128,27 @@ wish to hook into the
 system without modifying the user's other
 config files.
 .Pp
-All messages that
+Since
+.Xr devctl 4
+allows only one active reader,
 .Nm
-receives are forwarded to the
+multiplexes it, forwarding all events to any number of connected clients.
+Clients connect by opening the SOCK_SEQPACKET
 .Ux
 domain socket at
-.Pa /var/run/devd.pipe .
+.Pa /var/run/devd.seqpacket.pipe .
 .Sh FILES
-.Bl -tag -width ".Pa /var/run/devd.pipe" -compact
+.Bl -tag -width ".Pa /var/run/devd.seqpacket.pipe" -compact
 .It Pa /etc/devd.conf
 The default
 .Nm
 configuration file.
-.It Pa /var/run/devd.pipe
+.It Pa /var/run/devd.seqpacket.pipe
 The socket used by
 .Nm
 to communicate with its clients.
+.It Pa /var/run/devd.pipe
+A deprecated socket retained for use with old clients.
 .El
 .Sh SEE ALSO
 .Xr devctl 4 ,
index 908803c..a1c8060 100644 (file)
@@ -52,7 +52,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sbin/devd/devd.cc 262914 2014-03-07 23:30:48Z asomers $
+ * $FreeBSD: head/sbin/devd/devd.cc 270004 2014-08-14 22:33:56Z asomers $
  */
 
 /*
@@ -99,7 +99,8 @@
 #include "devd.h"              /* C compatible definitions */
 #include "devd.hh"             /* C++ class definitions */
 
-#define PIPE "/var/run/devd.pipe"
+#define STREAMPIPE "/var/run/devd.pipe"
+#define SEQPACKETPIPE "/var/run/devd.seqpacket.pipe"
 #define CF "/etc/devd.conf"
 #define SYSCTL "hw.bus.devctl_disable"
 
 
 using namespace std;
 
+typedef struct client {
+       int fd;
+       int socktype;
+} client_t;
+
 extern FILE *yyin;
 extern int lineno;
 
@@ -820,12 +826,12 @@ process_event(char *buffer)
 }
 
 int
-create_socket(const char *name)
+create_socket(const char *name, int socktype)
 {
        int fd, slen;
        struct sockaddr_un sun;
 
-       if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0)
+       if ((fd = socket(PF_LOCAL, socktype, 0)) < 0)
                err(1, "socket");
        bzero(&sun, sizeof(sun));
        sun.sun_family = AF_UNIX;
@@ -844,12 +850,13 @@ create_socket(const char *name)
 
 unsigned int max_clients = 10; /* Default, can be overriden on cmdline. */
 unsigned int num_clients;
-list<int> clients;
+
+list<client_t> clients;
 
 void
 notify_clients(const char *data, int len)
 {
-       list<int>::iterator i;
+       list<client_t>::iterator i;
 
        /*
         * Deliver the data to all clients.  Throw clients overboard at the
@@ -859,11 +866,17 @@ notify_clients(const char *data, int len)
         * kernel memory or tie up the limited number of available connections).
         */
        for (i = clients.begin(); i != clients.end(); ) {
-               if (write(*i, data, len) != len) {
+               int flags;
+               if (i->socktype == SOCK_SEQPACKET)
+                       flags = MSG_EOR;
+               else
+                       flags = 0;
+
+               if (send(i->fd, data, len, flags) != len) {
                        --num_clients;
-                       close(*i);
+                       close(i->fd);
                        i = clients.erase(i);
-                       devdlog(LOG_WARNING, "notify_clients: write() failed; "
+                       devdlog(LOG_WARNING, "notify_clients: send() failed; "
                            "dropping unresponsive client\n");
                } else
                        ++i;
@@ -875,7 +888,7 @@ check_clients(void)
 {
        int s;
        struct pollfd pfd;
-       list<int>::iterator i;
+       list<client_t>::iterator i;
 
        /*
         * Check all existing clients to see if any of them have disappeared.
@@ -886,12 +899,12 @@ check_clients(void)
         */
        pfd.events = 0;
        for (i = clients.begin(); i != clients.end(); ) {
-               pfd.fd = *i;
+               pfd.fd = i->fd;
                s = poll(&pfd, 1, 0);
                if ((s < 0 && s != EINTR ) ||
                    (s > 0 && (pfd.revents & POLLHUP))) {
                        --num_clients;
-                       close(*i);
+                       close(i->fd);
                        i = clients.erase(i);
                        devdlog(LOG_NOTICE, "check_clients:  "
                            "dropping disconnected client\n");
@@ -901,9 +914,9 @@ check_clients(void)
 }
 
 void
-new_client(int fd)
+new_client(int fd, int socktype)
 {
-       int s;
+       client_t s;
        int sndbuf_size;
 
        /*
@@ -912,13 +925,14 @@ new_client(int fd)
         * by sending large buffers full of data we'll never read.
         */
        check_clients();
-       s = accept(fd, NULL, NULL);
-       if (s != -1) {
+       s.socktype = socktype;
+       s.fd = accept(fd, NULL, NULL);
+       if (s.fd != -1) {
                sndbuf_size = CLIENT_BUFSIZE;
-               if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf_size,
+               if (setsockopt(s.fd, SOL_SOCKET, SO_SNDBUF, &sndbuf_size,
                    sizeof(sndbuf_size)))
                        err(1, "setsockopt");
-               shutdown(s, SHUT_RD);
+               shutdown(s.fd, SHUT_RD);
                clients.push_back(s);
                ++num_clients;
        } else
@@ -932,7 +946,7 @@ event_loop(void)
        int fd;
        char buffer[DEVCTL_MAXBUF];
        int once = 0;
-       int server_fd, max_fd;
+       int stream_fd, seqpacket_fd, max_fd;
        int accepting;
        timeval tv;
        fd_set fds;
@@ -940,9 +954,10 @@ event_loop(void)
        fd = open(PATH_DEVCTL, O_RDONLY | O_CLOEXEC);
        if (fd == -1)
                err(1, "Can't open devctl device %s", PATH_DEVCTL);
-       server_fd = create_socket(PIPE);
+       stream_fd = create_socket(STREAMPIPE, SOCK_STREAM);
+       seqpacket_fd = create_socket(SEQPACKETPIPE, SOCK_SEQPACKET);
        accepting = 1;
-       max_fd = max(fd, server_fd) + 1;
+       max_fd = max(fd, max(stream_fd, seqpacket_fd)) + 1;
        while (!romeo_must_die) {
                if (!once && !no_daemon && !daemonize_quick) {
                        // Check to see if we have any events pending.
@@ -963,24 +978,28 @@ event_loop(void)
                }
                /*
                 * When we've already got the max number of clients, stop
-                * accepting new connections (don't put server_fd in the set),
-                * shrink the accept() queue to reject connections quickly, and
-                * poll the existing clients more often, so that we notice more
-                * quickly when any of them disappear to free up client slots.
+                * accepting new connections (don't put the listening sockets in
+                * the set), shrink the accept() queue to reject connections
+                * quickly, and poll the existing clients more often, so that we
+                * notice more quickly when any of them disappear to free up
+                * client slots.
                 */
                FD_ZERO(&fds);
                FD_SET(fd, &fds);
                if (num_clients < max_clients) {
                        if (!accepting) {
-                               listen(server_fd, max_clients);
+                               listen(stream_fd, max_clients);
+                               listen(seqpacket_fd, max_clients);
                                accepting = 1;
                        }
-                       FD_SET(server_fd, &fds);
+                       FD_SET(stream_fd, &fds);
+                       FD_SET(seqpacket_fd, &fds);
                        tv.tv_sec = 60;
                        tv.tv_usec = 0;
                } else {
                        if (accepting) {
-                               listen(server_fd, 0);
+                               listen(stream_fd, 0);
+                               listen(seqpacket_fd, 0);
                                accepting = 0;
                        }
                        tv.tv_sec = 2;
@@ -1020,8 +1039,14 @@ event_loop(void)
                                break;
                        }
                }
-               if (FD_ISSET(server_fd, &fds))
-                       new_client(server_fd);
+               if (FD_ISSET(stream_fd, &fds))
+                       new_client(stream_fd, SOCK_STREAM);
+               /*
+                * Aside from the socket type, both sockets use the same
+                * protocol, so we can process clients the same way.
+                */
+               if (FD_ISSET(seqpacket_fd, &fds))
+                       new_client(seqpacket_fd, SOCK_SEQPACKET);
        }
        close(fd);
 }