<div dir="ltr"><div dir="ltr">On Mon, Sep 13, 2021 at 12:29 PM Ryan McClue <<a href="mailto:re.mcclue@protonmail.com">re.mcclue@protonmail.com</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div>Currently, I'm listening to NETLINK_KOBJECT_UEVENT messages with the following code:<br></div><div><br></div><div>union UeventBuffer {<br></div><div>  struct nlmsghdr netlink_header;<br></div><div>  char raw[8192];<br></div><div>};<br></div><div>  int sock = socket(PF_NETLINK, SOCK_RAW | SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT);<br></div><div><br></div><div>  struct sockaddr_nl addr = {};<br></div><div>  addr.nl_family = AF_NETLINK;<br></div><div>  addr.nl_groups = 1 << 0;<br></div><div>  bind(sock, (struct sockaddr *)&addr, sizeof(addr));<br></div><div><br></div><div>  UeventBuffer buf = {};<br></div><div>  struct iovec iov = {};<br></div><div>  iov.iov_base = &buf;<br></div><div>  iov.iov_len = sizeof(buf);<br></div><div><br></div><div>  struct msghdr msg = {};<br></div><div>  struct sockaddr_nl src_addr = {};<br></div><div>  msg.msg_name = &src_addr;<br></div><div>  msg.msg_namelen = sizeof(src_addr);<br></div><div>  msg.msg_iov = &iov;<br></div><div>  msg.msg_iovlen = 1;<br></div><div><br></div><div>  int bytes = recvmsg(sock, &msg, 0);<br></div><div>  char *buf_str = buf.raw;<br></div><div>  // parse this buf_str ...<br></div><div><br></div><div>I have a few questions to clarify my understanding and to make this more robust:<br></div><div><div>1. If I add an Xbox One controller, which evtest shows to be /dev/input/event14 I get a whole host of messages, e.g:<br></div><div><i>add@/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0</i><br></div></div><div><i>add@/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0/input/input38</i><br></div><div><i>add@/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0/input/input38/event14</i><br></div><div><i>add@/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0/input/input38/js0</i><br></div><div><i>bind@/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0</i><br></div><div><i>add@/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.4/1-2.4:1.1</i><br></div><div><i>add@/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.4/1-2.4:1.2</i><br></div><div><i>bind@/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.4</i><br></div><div><i>add@/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.2</i><br></div><div><i>change@/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.2</i><br></div><div><div>Why so many?</div></div></blockquote><div><br></div><div>It represents the actual device and subsystem layering in Linux – first there's a USB device (on hub 1-2 port 4), then USB interfaces on that device (1.0 to 1.2), then an input-layer device (input38), then two different /dev nodes exposed by it (generic evdev and what I *think* is legacy joydev? Not sure if it's "legacy" or "still current".)</div><div><br></div><div>They are necessary; for example, the 1st event that informs systemd-udevd about the low-level USB device is what causes the correct device driver module to be loaded in the first place.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><div> Can I filter them to just get the ones ending with /input/inputXX/eventXX?<br></div></div></blockquote><div><br></div><div>It seems you're supposed to use BPF filters via SO_ATTACH_FILTER; at least that's what libudev does.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><div></div></div><div>2.
 Currently this only picks up input devices. How would I listen to /snd
devices, /hid devices, etc.? I assume some change to nl_groups, however
what should this be and where is this documented?<br></div></blockquote><div><br></div><div>There's just one group for all events.</div><div><br></div><div>(If I remember correctly, group 1 has all events straight from the kernel, group 2 is the same events augmented and retransmitted by udev. Normally programs want the latter. Both have the same events and include all devices, though.)</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div></div><div>3.
Currently, I'm manually parsing the <b>buf_str</b> to extract the command and
device. Are there some supplied macros that parse this information in a
more robust way? (as is the case for RTNETLINK)<br></div></blockquote><div><br></div><div>Well, systemd supplies a whole libudev library, so I would generally recommend using that – *instead of* manually working with netlink... (Or more recently sd-device, but I don't think libudev is likely to be going *poof* anytime soon, especially if you're looking for compatibility with older systems or eudev-using distros.)</div><div><br></div><div>Start with udev_monitor_new_from_netlink() and use udev_monitor_filter_add_match_*() to filter by subsystem, devtype, or some arbitrary property, then you'll receive events already parsed. That's 3 lines of code in comparison to your 30.</div></div><div><br></div>-- <br><div dir="ltr" class="gmail_signature"><div dir="ltr">Mantas Mikulėnas</div></div></div>