Compare commits
2 Commits
4512b33fa9
...
0e25a32850
Author | SHA1 | Date |
---|---|---|
Emery Hemingway | 0e25a32850 | |
Emery Hemingway | f51f92c30d |
|
@ -0,0 +1 @@
|
||||||
|
/nim.cfg
|
|
@ -0,0 +1,3 @@
|
||||||
|
include_rules
|
||||||
|
: |> !nim_lk |> {lockfile}
|
||||||
|
: {lockfile} |> !nim_cfg |> | ./<lock>
|
|
@ -1,2 +1,4 @@
|
||||||
include ../syndicate-nim/depends.tup
|
include ../syndicate-nim/depends.tup
|
||||||
|
NIM = $(DIRENV) $(NIM)
|
||||||
NIM_FLAGS += --path:$(TUP_CWD)/../syndicate-nim/src
|
NIM_FLAGS += --path:$(TUP_CWD)/../syndicate-nim/src
|
||||||
|
NIM_GROUPS += $(TUP_CWD)/<lock>
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
{ pkgs ? import <nixpkgs> { } }:
|
||||||
|
|
||||||
|
pkgs.buildNimPackage {
|
||||||
|
name = "syndicate_utils_linux";
|
||||||
|
lockFile = ./lock.json;
|
||||||
|
src = pkgs.lib.sources.cleanSource ./.;
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
{
|
||||||
|
"depends": [
|
||||||
|
{
|
||||||
|
"method": "fetchzip",
|
||||||
|
"packages": [
|
||||||
|
"bigints"
|
||||||
|
],
|
||||||
|
"path": "/nix/store/jvrm392g8adfsgf36prgwkbyd7vh5jsw-source",
|
||||||
|
"rev": "86ea14d31eea9275e1408ca34e6bfe9c99989a96",
|
||||||
|
"sha256": "15pcpmnk1bnw3k8769rjzcpg00nahyrypwbxs88jnwr4aczp99j4",
|
||||||
|
"srcDir": "src",
|
||||||
|
"url": "https://github.com/ehmry/nim-bigints/archive/86ea14d31eea9275e1408ca34e6bfe9c99989a96.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "fetchzip",
|
||||||
|
"packages": [
|
||||||
|
"cps"
|
||||||
|
],
|
||||||
|
"path": "/nix/store/452hfhasrn3gl6vijfmzs69djl099j0j-source",
|
||||||
|
"rev": "b7c179f172e3a256a482a9daee3c0815ea423206",
|
||||||
|
"sha256": "1sn9s7iv83sw1jl5jgi2h7b0xpgsn13f9icp5124jvbp0qkxskx2",
|
||||||
|
"srcDir": "",
|
||||||
|
"url": "https://github.com/nim-works/cps/archive/b7c179f172e3a256a482a9daee3c0815ea423206.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "fetchzip",
|
||||||
|
"packages": [
|
||||||
|
"hashlib"
|
||||||
|
],
|
||||||
|
"path": "/nix/store/fav82xdbicvlk34nmcbl89zx99lr3mbs-source",
|
||||||
|
"rev": "f9455d4be988e14e3dc7933eb7cc7d7c4820b7ac",
|
||||||
|
"sha256": "1sx6j952lj98629qfgr7ds5aipyw9d6lldcnnqs205wpj4pkcjb3",
|
||||||
|
"srcDir": "",
|
||||||
|
"url": "https://github.com/khchen/hashlib/archive/f9455d4be988e14e3dc7933eb7cc7d7c4820b7ac.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "fetchzip",
|
||||||
|
"packages": [
|
||||||
|
"nimcrypto"
|
||||||
|
],
|
||||||
|
"path": "/nix/store/jwz8pqbv6rsm8w4fjzdb37r0wzjn5hv0-source",
|
||||||
|
"rev": "d58da671799c69c0b3208b96c154e13c8b1a9e90",
|
||||||
|
"sha256": "12dm0gsy10ppga7zf7hpf4adaqjrd9b740n2w926xyazq1njf6k9",
|
||||||
|
"srcDir": "",
|
||||||
|
"url": "https://github.com/cheatfate/nimcrypto/archive/d58da671799c69c0b3208b96c154e13c8b1a9e90.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "fetchzip",
|
||||||
|
"packages": [
|
||||||
|
"npeg"
|
||||||
|
],
|
||||||
|
"path": "/nix/store/ffkxmjmigfs7zhhiiqm0iw2c34smyciy-source",
|
||||||
|
"rev": "26d62fdc40feb84c6533956dc11d5ee9ea9b6c09",
|
||||||
|
"sha256": "0xpzifjkfp49w76qmaylan8q181bs45anmp46l4bwr3lkrr7bpwh",
|
||||||
|
"srcDir": "src",
|
||||||
|
"url": "https://github.com/zevv/npeg/archive/26d62fdc40feb84c6533956dc11d5ee9ea9b6c09.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "fetchzip",
|
||||||
|
"packages": [
|
||||||
|
"preserves"
|
||||||
|
],
|
||||||
|
"path": "/nix/store/2hy124xgabz134dxj3wji7mp47fdwy3w-source",
|
||||||
|
"rev": "9ae435a83c6d5028405538af5d24a023af625b6e",
|
||||||
|
"sha256": "1k7ywcp1a53x2fpc6wc2b0qzb264dkifash0s1wcp66rw3lx15k2",
|
||||||
|
"srcDir": "src",
|
||||||
|
"url": "https://git.syndicate-lang.org/ehmry/preserves-nim/archive/9ae435a83c6d5028405538af5d24a023af625b6e.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "fetchzip",
|
||||||
|
"packages": [
|
||||||
|
"stew"
|
||||||
|
],
|
||||||
|
"path": "/nix/store/mqg8qzsbcc8xqabq2yzvlhvcyqypk72c-source",
|
||||||
|
"rev": "3c91b8694e15137a81ec7db37c6c58194ec94a6a",
|
||||||
|
"sha256": "17lfhfxp5nxvld78xa83p258y80ks5jb4n53152cdr57xk86y07w",
|
||||||
|
"srcDir": "",
|
||||||
|
"url": "https://github.com/status-im/nim-stew/archive/3c91b8694e15137a81ec7db37c6c58194ec94a6a.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "fetchzip",
|
||||||
|
"packages": [
|
||||||
|
"syndicate"
|
||||||
|
],
|
||||||
|
"path": "/nix/store/y9f3j4m7vmhf8gbpkvqa77jvzrc5ynlm-source",
|
||||||
|
"rev": "50a77995bcfe15e6062f54c6af0f55fba850c329",
|
||||||
|
"sha256": "1avrk86c34qg39w8vlixsksli2gwgbsf29jhlap27ffzdbj2zbal",
|
||||||
|
"srcDir": "src",
|
||||||
|
"url": "https://git.syndicate-lang.org/ehmry/syndicate-nim/archive/50a77995bcfe15e6062f54c6af0f55fba850c329.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "fetchzip",
|
||||||
|
"packages": [
|
||||||
|
"sys"
|
||||||
|
],
|
||||||
|
"path": "/nix/store/anfijq8zsfvhcy86dx21n8ikh3z8927s-source",
|
||||||
|
"rev": "b974e1a4ca6ae7d89fc9e7b3714b1e7daf6f33e5",
|
||||||
|
"sha256": "13js2plyf34bdv9rwhbjkgygmyb89h43cf3z126yjsm2fvh2sl10",
|
||||||
|
"srcDir": "src",
|
||||||
|
"url": "https://github.com/ehmry/nim-sys/archive/b974e1a4ca6ae7d89fc9e7b3714b1e7daf6f33e5.tar.gz"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,5 +0,0 @@
|
||||||
let
|
|
||||||
syndicate = builtins.getFlake "syndicate";
|
|
||||||
pkgs =
|
|
||||||
import <nixpkgs> { overlays = builtins.attrValues syndicate.overlays; };
|
|
||||||
in pkgs.acpi_actor
|
|
|
@ -1,3 +1,3 @@
|
||||||
include_rules
|
include_rules
|
||||||
: syndev.nim | $(SYNDICATE_PROTOCOL) |> !nim_bin |> {bin}
|
: foreach *.nim | $(SYNDICATE_PROTOCOL) |> !nim_bin |> {bin}
|
||||||
: {bin} |> !assert_built |>
|
: {bin} |> !assert_built |>
|
||||||
|
|
|
@ -1,98 +0,0 @@
|
||||||
# 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", "".toPreserve, "".toPreserve, "".toSymbol, initDictionary(), 0.toPreserve)
|
|
||||||
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:
|
|
||||||
let sep = buf[i]
|
|
||||||
inc i, parseUntil(buf, val, '\0', i+1)+1
|
|
||||||
case sep
|
|
||||||
of '@':
|
|
||||||
if msg.record[3].dict.len > 0:
|
|
||||||
cannonicalize(msg.record[3])
|
|
||||||
message(turn, ds, msg)
|
|
||||||
msg.record[3].dict.setLen(0)
|
|
||||||
of '=':
|
|
||||||
if key == "SUBSYSTEM":
|
|
||||||
msg.record[0].string = val
|
|
||||||
elif key == "DEVPATH":
|
|
||||||
msg.record[1].string = val
|
|
||||||
elif key == "ACTION":
|
|
||||||
msg.record[2].symbol = Symbol val
|
|
||||||
elif key == "SEQNUM":
|
|
||||||
discard parseBiggestInt(val, msg.record[4].int)
|
|
||||||
else:
|
|
||||||
# TODO: check if val can be an integer
|
|
||||||
var num: BiggestInt
|
|
||||||
if parseBiggestInt(val, num) == val.len:
|
|
||||||
add(msg.record[3].dict, (key.toSymbol, num.toPreserve,))
|
|
||||||
else:
|
|
||||||
add(msg.record[3].dict, (key.toSymbol, val.toPreserve,))
|
|
||||||
val.setLen(0)
|
|
||||||
else:
|
|
||||||
stderr.writeLine "uevent parser synchronization lost"
|
|
||||||
break
|
|
||||||
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,106 @@
|
||||||
|
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
||||||
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
|
# *Do not misinterpret any of this as documentation for handling Linux uevents.*
|
||||||
|
|
||||||
|
import std/[nativesockets, os, parseutils, posix]
|
||||||
|
import pkg/sys/[handles, ioqueue, sockets]
|
||||||
|
import preserves, syndicate, syndicate/relays
|
||||||
|
|
||||||
|
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: uint32): 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: SocketHandle =
|
||||||
|
result = createNativeSocket(
|
||||||
|
cint AF_NETLINK,
|
||||||
|
cint posix.SOCK_DGRAM,
|
||||||
|
NETLINK_KOBJECT_UEVENT,
|
||||||
|
)
|
||||||
|
var sa = initSockaddr(pid = uint32 getPid(), groups = 1)
|
||||||
|
if bindAddr(result, 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 openUeventSocketAsync: AsyncConn[sockets.Protocol.Unix] =
|
||||||
|
let fd = openUeventSocket()
|
||||||
|
var flags = fcntl(fd.cint, F_GETFL)
|
||||||
|
if flags < 0:
|
||||||
|
raiseOSError(osLastError())
|
||||||
|
flags = flags or O_NONBLOCK
|
||||||
|
if fcntl(fd.cint, F_SETFL, flags) < 0:
|
||||||
|
raiseOSError(osLastError())
|
||||||
|
AsyncConn[sockets.Protocol.Unix] fd.SocketFD.initHandle.newAsyncSocket
|
||||||
|
|
||||||
|
proc sendMessage(turn: var Turn; ds: Cap; buf: string; n: int) =
|
||||||
|
var
|
||||||
|
msg = initRecord("uevent", toPreserves"", toPreserves"", toSymbol"", initDictionary(), 0.toPreserves)
|
||||||
|
key, val: string
|
||||||
|
i = 0
|
||||||
|
while i < n:
|
||||||
|
inc i, skipWhile(buf, {'\0'}, i)
|
||||||
|
inc i, parseUntil(buf, key, {'=', '@'}, i)
|
||||||
|
if i < n:
|
||||||
|
let sep = buf[i]
|
||||||
|
inc i, parseUntil(buf, val, '\0', i+1)+1
|
||||||
|
case sep
|
||||||
|
of '@': discard
|
||||||
|
of '=':
|
||||||
|
if key == "SUBSYSTEM":
|
||||||
|
msg.record[0].string = val
|
||||||
|
elif key == "DEVPATH":
|
||||||
|
msg.record[1].string = val
|
||||||
|
elif key == "ACTION":
|
||||||
|
msg.record[2].symbol = Symbol val
|
||||||
|
elif key == "SEQNUM":
|
||||||
|
msg.record[4] = parsePreserves(val)
|
||||||
|
else:
|
||||||
|
# TODO: check if val can be an integer
|
||||||
|
var num: BiggestInt
|
||||||
|
if parseBiggestInt(val, num) == val.len:
|
||||||
|
add(msg.record[3].dict, (key.toSymbol, num.toPreserve,))
|
||||||
|
else:
|
||||||
|
add(msg.record[3].dict, (key.toSymbol, val.toPreserve,))
|
||||||
|
val.setLen(0)
|
||||||
|
else:
|
||||||
|
stderr.writeLine "uevent parser failure"
|
||||||
|
return
|
||||||
|
if msg.record[3].dict.len > 0:
|
||||||
|
cannonicalize(msg.record[3])
|
||||||
|
message(turn, ds, msg)
|
||||||
|
msg.record[3].dict.setLen(0)
|
||||||
|
|
||||||
|
proc loop(facet: Facet; ds: Cap; sock: AsyncConn[sockets.Protocol.Unix]) {.asyncio.} =
|
||||||
|
let buf = new string
|
||||||
|
buf[].setLen(16 shl 10)
|
||||||
|
while true:
|
||||||
|
let n = read(sock, buf)
|
||||||
|
if n < 1: stopActor(facet)
|
||||||
|
else:
|
||||||
|
proc act(turn: var Turn) =
|
||||||
|
sendMessage(turn, ds, buf[], n)
|
||||||
|
run(facet, act)
|
||||||
|
|
||||||
|
runActor("uevent_dump") do (turn: var Turn):
|
||||||
|
let sock = openUeventSocketAsync()
|
||||||
|
onStop(turn) do (turn: var Turn):
|
||||||
|
close(sock)
|
||||||
|
resolveEnvironment(turn) do (turn: var Turn; ds: Cap):
|
||||||
|
discard trampoline:
|
||||||
|
whelp loop(turn.facet, ds, sock)
|
|
@ -1,13 +1,13 @@
|
||||||
# Package
|
# Package
|
||||||
|
|
||||||
version = "20230704"
|
version = "20240315"
|
||||||
author = "Emery Hemingway"
|
author = "Emery Hemingway"
|
||||||
description = "Syndicated actor for publishing Linux device events"
|
description = "Syndicate utilties for Linux."
|
||||||
license = "Unlicense"
|
license = "Unlicense"
|
||||||
srcDir = "src"
|
srcDir = "src"
|
||||||
bin = @["syndev"]
|
bin = @["uevent_dump"]
|
||||||
|
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|
||||||
requires "nim >= 1.6.12", "syndicate >= 20230701"
|
requires "nim >= 1.6.12", "syndicate >= 20240208", "https://github.com/ehmry/nim-sys.git#b974e1a4ca6ae7d89fc9e7b3714b1e7daf6f33e5", "https://github.com/nim-works/cps"
|
||||||
|
|
Loading…
Reference in New Issue