:: [DNG] nlmon (was: A better default…
トップ ページ
このメッセージを削除
このメッセージに返信
著者: Rainer Weikusat
日付:  
To: dng
古いトピック: Re: [DNG] A better default windows manager
題目: [DNG] nlmon (was: A better default windows manager)
Isaac Dunham <ibid.ag@???> writes:
> Or you can do it with mount, sudo, sh, and nlmon (http://git.r-36.net/nlmon).


Using poll to wait for a message followed by recvmsg for reading it
offers (in absence of a timeout) no advantages over just doing a
blocking recv. Since this code neither uses control messages nor looks
at the returned flags, it can use recvfrom instead of the (more
complicated) recvmsg. Considering that it checks for message buffer
overflow via len >= sizeof(buf), the MSG_TRUNC flag should probably be
used to make the kernel return the real size in case a datagram was
truncated. Lastly, the message doesn't have to be copied to a 2nd buffer
just to turn the 0-terminated name=value pairs into \n-terminated ones.

NB: I admit that I mainly did this because it looked like a nice, simple
programming task.

------------
diff --git a/nlmon.c b/nlmon.c
index 7339f74..8e965fe 100644
--- a/nlmon.c
+++ b/nlmon.c
@@ -53,15 +53,50 @@ usage(void)
     die("usage: %s [-h] [-kl] [-f subsystem]\n", argv0);
 }


+void
+print_event_if(char *subsys, char *p, int len)
+{
+    char *s, *e, *sep;
+    char *start;
+
+    start = p;
+    e = p + len;
+
+    /* find start of name=value pairs */
+    while (++p < e && *p != '=')
+        if (!*p) start = s = p + 1;
+    if (p == e) return;
+
+    do {
+        sep = p;
+
+        /* skip to end of parameter */
+        do ++p; while (p < e && *p);
+        if (p == e) return;
+         
+        if (subsys && strncmp("SUBSYSTEM", s, sep - s) == 0) {
+            if (strcmp(sep + 1, subsys) != 0) return;
+            subsys = NULL;
+        }
+
+        *p = '\n';
+
+        /* find next = */
+        s = ++p;
+        while (p < e && *p != '=') ++p;
+    } while (p < e);
+
+    *p++ = '\n';
+    write(1, start, p - start);
+}
+
 int
 main(int argc, char *argv[])
 {
     struct sockaddr_nl nls, cnls;
-    struct pollfd fds;
-    struct msghdr hdr;
-    struct iovec iov;
-    char buf[4097], obuf[4098], *subsystem;
-    int i, len, olen, slen, showudev, showkernel;
+    socklen_t cnlslen;
+    char buf[4097], *subsystem;
+    int len, showudev, showkernel, sk;


     showkernel = 1;
     showudev = 1;
@@ -93,9 +128,8 @@ main(int argc, char *argv[])
      * messages in userspace.
      */


-    fds.events = POLLIN;
-    fds.fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
-    if (fds.fd < 0)
+    sk = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+    if (sk < 0)
         edie("socket");


     /*
@@ -104,20 +138,15 @@ main(int argc, char *argv[])
      * enough buffer.
      */


-    if (bind(fds.fd, (void *)&nls, sizeof(nls)))
+    if (bind(sk, (void *)&nls, sizeof(nls)))
         edie("bind");


-    buf[sizeof(buf)-1] = '\0';
-    while (poll(&fds, 1, -1) > -1) {
-        iov.iov_base = &buf;
-        iov.iov_len = sizeof(buf);
-        memset(&hdr, 0, sizeof(hdr));
-        hdr.msg_iov = &iov;
-        hdr.msg_iovlen = 1;
-        hdr.msg_name = &cnls;
-        hdr.msg_namelen = sizeof(cnls);
-
-        len = recvmsg(fds.fd, &hdr, 0);
+    while (1) {
+        buf[sizeof(buf)-1] = '\0';
+        cnlslen = sizeof(cnls);
+        len = recvfrom(sk, buf, sizeof(buf), MSG_TRUNC,
+            (struct sockaddr *)&cnls, &cnlslen);
+        
         if (len < 0) {
             if (errno == EINTR)
                 continue;
@@ -126,40 +155,10 @@ main(int argc, char *argv[])
         if (len < 32 || len >= sizeof(buf))
             continue;


-        if (!memcmp(buf, "libudev", 8)) {
-            if (!showudev)
-                continue;
-        } else {
-            if (!showkernel)
-                continue;
-
-            /*
-             * Kernel messages should be from root.
-             */
-            if (cnls.nl_pid > 0)
-                continue;
-        }
-
-        for (i = 0, olen = 0; i < len; i += slen + 1) {
-            slen = strlen(buf+i);
-            if (!slen || !strchr(buf+i, '='))
-                continue;
-            if (subsystem && !strncmp(buf+i, "SUBSYSTEM=", 10)
-                    && !strstr(buf+i+10, subsystem)) {
-                olen = 0;
-                break;
-            }
-
-            snprintf(obuf+olen, sizeof(obuf)-olen-2,
-                    "%s\n", buf+i);
-            olen += slen + 1;
-        }
-        if (olen > 0) {
-            obuf[olen] = '\n';
-            write(1, obuf, olen+1);
-        }
+        if ((showudev && memcmp(buf, "libudev", 8) == 0)
+            || (showkernel && cnls.nl_pid < 1)) 
+            print_event_if(subsystem, buf, len);
     }


     return 0;
 }
-