Initial commit
This commit is contained in:
commit
9906654543
|
@ -0,0 +1,36 @@
|
|||
# Syndicated Device Event Broadcaster
|
||||
|
||||
An actor for broadcasting Linux Kernel uevents.
|
||||
|
||||
Intended as part of native a device manager for [Synit](https://synit.org). This is not a replacement for udev/eudev or mdev/mdevd.
|
||||
|
||||
Message Schema is at [./uevent.prs](./uevent.prs).
|
||||
|
||||
If you are looking for documentation on how to parse and handle Linux uevents, please let me know when you find it.
|
||||
|
||||
Example Syndicate server configuration:
|
||||
```
|
||||
? <machine-dataspace ?machine> [
|
||||
|
||||
<require-service <daemon syndev>>
|
||||
|
||||
<daemon syndev {
|
||||
argv: ["/bin/syndev"]
|
||||
protocol: application/syndicate
|
||||
}>
|
||||
|
||||
? <service-object <daemon syndev> ?cap> [
|
||||
$cap { machine: $machine }
|
||||
]
|
||||
]
|
||||
|
||||
```
|
||||
|
||||
Example message stream:
|
||||
```
|
||||
<uevent 32663 add {DEVNAME: "input/event23", DEVPATH: "/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.4/0003:1D50:6122.0026/input/input47/event23", MAJOR: "13", MINOR: "87", SUBSYSTEM: "input"}>
|
||||
<uevent 32664 add {DEVNAME: "input/mouse5", DEVPATH: "/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.4/0003:1D50:6122.0026/input/input47/mouse5", MAJOR: "13", MINOR: "37", SUBSYSTEM: "input"}>
|
||||
<uevent 32665 add {DEVNAME: "hidraw10", DEVPATH: "/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.4/0003:1D50:6122.0026/hidraw/hidraw10", MAJOR: "247", MINOR: "10", SUBSYSTEM: "hidraw"}>
|
||||
<uevent 32666 bind {DEVPATH: "/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.4/0003:1D50:6122.0026", DRIVER: "hid-generic", HID_ID: "0003:00001D50:00006122", HID_NAME: "Ultimate Gadget Laboratories Ultimate Hacking Keyboard", HID_PHYS: "usb-0000:00:14.0-3/input4", HID_UNIQ: "", MODALIAS: "hid:b0003g0001v00001D50p00006122", SUBSYSTEM: "hid"}>
|
||||
<uevent 32667 bind {DEVPATH: "/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.4", DEVTYPE: "usb_interface", DRIVER: "usbhid", INTERFACE: "3/1/2", MODALIAS: "usb:v1D50p6122d0101dc00dsc00dp00ic03isc01ip02in04", PRODUCT: "1d50/6122/101", SUBSYSTEM: "usb", TYPE: "0/0/0"}>
|
||||
```
|
|
@ -0,0 +1,2 @@
|
|||
include ../syndicate-nim/depends.tup
|
||||
NIM_FLAGS += --path:$(TUP_CWD)/../syndicate-nim/src
|
|
@ -0,0 +1,5 @@
|
|||
let
|
||||
syndicate = builtins.getFlake "syndicate";
|
||||
pkgs =
|
||||
import <nixpkgs> { overlays = builtins.attrValues syndicate.overlays; };
|
||||
in pkgs.acpi_actor
|
|
@ -0,0 +1,3 @@
|
|||
include_rules
|
||||
: syndev.nim | $(SYNDICATE_PROTOCOL) |> !nim_bin |> {bin}
|
||||
: {bin} |> !assert_built |>
|
|
@ -0,0 +1,86 @@
|
|||
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
||||
# SPDX-License-Identifier: Unlicense
|
||||
|
||||
# *Do not misinterpret any of this as documentation for handling Linux uevents.*
|
||||
|
||||
import std/[asyncdispatch, nativesockets, asyncnet, os, parseutils, posix]
|
||||
import preserves, syndicate
|
||||
|
||||
var
|
||||
AF_NETLINK {.importc, header: "sys/socket.h", nodecl.}: uint16
|
||||
NETLINK_KOBJECT_UEVENT {.importc, header: "linux/netlink.h", nodecl.}: cint
|
||||
|
||||
type
|
||||
Sockaddr_nl {.importc: "struct sockaddr_nl", header: "linux/netlink.h".} = object
|
||||
nl_family: uint16
|
||||
nl_pad: uint16
|
||||
nl_pid: uint32
|
||||
nl_groups: uint32
|
||||
|
||||
proc initSockaddr(family = AF_NETLINK; pid, groups = 0'u32): Sockaddr_nl =
|
||||
Sockaddr_nl(nl_family: family, nl_pid: pid, nl_groups: groups)
|
||||
|
||||
proc saddr(sa_nl: var Sockaddr_nl): ptr Sockaddr =
|
||||
cast[ptr Sockaddr](addr sa_nl)
|
||||
|
||||
proc openUeventSocket: AsyncSocket =
|
||||
result = newAsyncSocket(
|
||||
cint AF_NETLINK,
|
||||
posix.SOCK_DGRAM,
|
||||
NETLINK_KOBJECT_UEVENT,
|
||||
buffered = false
|
||||
)
|
||||
var sa = initSockaddr(pid = uint32 getPid(), groups = 1)
|
||||
if bindAddr(result.getFd, saddr sa, SockLen sizeof(sa)) != 0:
|
||||
close(result)
|
||||
raiseOSError(osLastError(), "failed to bind Netlink socket")
|
||||
if sa.nl_family != AF_NETLINK:
|
||||
close(result)
|
||||
raise newException(IOError, "Netlink not supported")
|
||||
|
||||
proc main(facet: Facet; ds: Ref; sock: AsyncSocket) =
|
||||
var
|
||||
buf = newString(1 shl 14)
|
||||
msg = initRecord("uevent", 0.toPreserve, "".toSymbol, initDictionary())
|
||||
key, val: string
|
||||
proc recvUevent {.gcsafe.} =
|
||||
let fut = recvInto(sock, buf[0].addr, buf.len)
|
||||
addCallback(fut, facet) do (turn: var Turn):
|
||||
let n = read fut
|
||||
if n < 1:
|
||||
close(sock)
|
||||
else:
|
||||
var i = 0
|
||||
while i < n:
|
||||
inc i, skipWhile(buf, {'\0'}, i)
|
||||
inc i, parseUntil(buf, key, {'=', '@'}, i)
|
||||
if i < n:
|
||||
if buf[i] == '@':
|
||||
if msg.record[2].dict.len > 0:
|
||||
cannonicalize(msg.record[1])
|
||||
message(turn, ds, msg)
|
||||
msg.record[2].dict.setLen(0)
|
||||
inc i, parseUntil(buf, val, '\0', i+1)+1
|
||||
elif key == "SEQNUM":
|
||||
var seqnum: int
|
||||
inc i, parseInt(buf, seqnum, i+1)+1
|
||||
msg.record[0].int = seqnum.BiggestInt
|
||||
else:
|
||||
inc i, parseUntil(buf, val, '\0', i+1)+1
|
||||
if key == "ACTION":
|
||||
msg.record[1].symbol = Symbol val
|
||||
else:
|
||||
add(msg.record[2].dict, (key.toSymbol, val.toPreserve,))
|
||||
recvUevent()
|
||||
recvUevent()
|
||||
|
||||
type Args {.preservesDictionary.} = object
|
||||
machine: Ref
|
||||
|
||||
runActor("syndev") do (root: Ref; turn: var Turn):
|
||||
connectStdio(root, turn)
|
||||
during(turn, root, ?Args) do (machine: Ref):
|
||||
let sock = openUeventSocket()
|
||||
main(turn.facet, machine, sock)
|
||||
do:
|
||||
close(sock)
|
|
@ -0,0 +1,13 @@
|
|||
# Package
|
||||
|
||||
version = "20230702"
|
||||
author = "Emery Hemingway"
|
||||
description = "Syndicated actor for publishing Linux device events"
|
||||
license = "Unlicense"
|
||||
srcDir = "src"
|
||||
bin = @["syndev"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.6.12", "syndicate >= 20230701"
|
|
@ -0,0 +1,3 @@
|
|||
version 1.
|
||||
|
||||
Uevent = <uvent @seqnum int @action string @attrs {symbol: string ...:...}> .
|
Loading…
Reference in New Issue