Update to recent Syndicate Nim API

This commit is contained in:
Emery Hemingway 2024-08-06 18:23:46 +01:00
parent 0e25a32850
commit afb7d9c2a4
15 changed files with 986 additions and 65 deletions

2
.envrc
View file

@ -1,2 +0,0 @@
source_env ..
use nix

View file

@ -1,29 +1,38 @@
# Syndicated Device Event Broadcaster
# Synit device managment toolkit
An actor for broadcasting Linux Kernel uevents.
Intended as a kit for building native a device manager for [Synit](https://synit.org).
This is not a replacement for udev/eudev or mdev/mdevd.
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).
Message Schema is at [uevents.prs](./uevents.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:
Example configuration for logging uevents:
```
? <machine-dataspace ?machine> [
#!/usr/bin/env -S syndicate-server --config
<require-service <daemon syndev>>
<daemon syndev {
argv: ["/bin/syndev"]
protocol: application/syndicate
}>
? <service-object <daemon syndev> ?cap> [
$cap { machine: $machine }
<q <service uevent-dump>>
? <a <service uevent-dump> <accepted ?stream>> [
$stream ?? ?msg [
$log ! <log "uevent" { line: ?msg }>
]
]
? <q <service uevent-dump>> [
<require-service <daemon dump-uevent>>
? <service-object <daemon dump-uevent> ?obj> [
let ?rewriter = <* $config [<rewrite ?resp <a <service uevent-dump> $resp>>]>
$obj <resolve <uevent-dump> $rewriter>
]
]
<daemon dump-uevent {
argv: ["/bin/dump-uevent" ]
clearEnv: #t
env: { BUILD_SUM: $sum }
protocol: application/syndicate
}>
```
Example message stream:

View file

@ -1,3 +1,6 @@
include_rules
: |> !nim_lk |> {lockfile}
: {lockfile} |> !nim_cfg |> | ./<lock>
: sbom.json |> !sbom-to-nix |> | ./<lock>
run ./Tuprules.jq sbom.json
: foreach {bin} |> !assert_built |>

12
Tuprules.jq Executable file
View file

@ -0,0 +1,12 @@
#! /usr/bin/env -S jq --raw-output --from-file
.metadata.component.properties as $props |
$props |
( map( select(.name | .[0:10] == "nim:binDir") ) +
map( select(.name | .[0:10] == "nim:srcDir") ) |
map( .value )
) + ["."] | .[0] as $binDir |
$props |
map( select(.name | .[0:8] == "nim:bin:") ) |
map( ": \($binDir)/\(.value).nim |> !nim_bin |> $(BIN_DIR)/\(.name[8:]) {bin}" ) |
join("\n")

View file

@ -1,4 +1,6 @@
include ../syndicate-nim/depends.tup
NIM = $(DIRENV) $(NIM)
NIM_FLAGS += --path:$(TUP_CWD)/../syndicate-nim/src
NIM_GROUPS += $(TUP_CWD)/<lock>
PROJECT_DIR = $(TUP_CWD)
NIM_GROUPS += $(SYNDICATE_PROTOCOL)
NIM_GROUPS += $(PROJECT_DIR)/<lock>
NIM_GROUPS += $(PROJECT_DIR)/<schema>

192
build-nim-sbom.nix Normal file
View file

@ -0,0 +1,192 @@
{
lib,
stdenv,
fetchgit,
fetchzip,
runCommand,
xorg,
nim,
nimOverrides,
}:
let
fetchers = {
fetchzip =
{ url, sha256, ... }:
fetchzip {
name = "source";
inherit url sha256;
};
fetchgit =
{
fetchSubmodules ? false,
leaveDotGit ? false,
rev,
sha256,
url,
...
}:
fetchgit {
inherit
fetchSubmodules
leaveDotGit
rev
sha256
url
;
};
};
filterPropertiesToAttrs =
prefix: properties:
lib.pipe properties [
(builtins.filter ({ name, ... }: (lib.strings.hasPrefix prefix name)))
(map (
{ name, value }:
{
name = lib.strings.removePrefix prefix name;
inherit value;
}
))
builtins.listToAttrs
];
buildNimCfg =
{ backend, components, ... }:
let
componentSrcDirs = map (
{ properties, ... }:
let
fodProps = filterPropertiesToAttrs "nix:fod:" properties;
fod = fetchers.${fodProps.method} fodProps;
srcDir = fodProps.srcDir or "";
in
if srcDir == "" then fod else "${fod}/${srcDir}"
) components;
in
runCommand "nim.cfg"
{
outputs = [
"out"
"src"
];
nativeBuildInputs = [ xorg.lndir ];
}
''
pkgDir=$src/pkg
cat << EOF >> $out
backend:${backend}
path:"$src"
path:"$pkgDir"
EOF
mkdir -p "$pkgDir"
${lib.strings.concatMapStrings (d: ''
lndir "${d}" "$pkgDir"
'') componentSrcDirs}
'';
buildCommands = lib.attrsets.mapAttrsToList (
output: input: ''
nim compile $nimFlags --out:${output} ${input}
''
);
installCommands = lib.attrsets.mapAttrsToList (
output: input: ''
install -Dt $out/bin ${output}
''
);
applySbom =
sbom:
{
passthru ? { },
...
}@prevAttrs:
let
properties = # SBOM metadata.component.properties as an attrset.
lib.attrsets.recursiveUpdate (builtins.listToAttrs sbom.metadata.component.properties)
passthru.properties or { };
nimBin = # A mapping of Nim module file paths to names of programs.
lib.attrsets.recursiveUpdate (lib.pipe properties [
(lib.attrsets.filterAttrs (name: value: lib.strings.hasPrefix "nim:bin:" name))
(lib.attrsets.mapAttrs' (
name: value: {
name = lib.strings.removePrefix "nim:bin:" name;
value = "${properties."nim:binDir" or (properties."nim:srcDir" or ".")}/${value}";
}
))
]) passthru.nimBin or { };
in
{
strictDeps = true;
pname = prevAttrs.pname or sbom.metadata.component.name;
version = prevAttrs.version or sbom.metadata.component.version or null;
configurePhase =
prevAttrs.configurePhase or ''
runHook preConfigure
echo "nim.cfg << $nimCfg"
cat $nimCfg >> nim.cfg
cat << EOF >> nim.cfg
nimcache:"$NIX_BUILD_TOP/nimcache"
parallelBuild:$NIX_BUILD_CORES
EOF
runHook postConfigure
'';
buildPhase =
prevAttrs.buildPhase or ''
runHook preBuild
${lib.strings.concatLines (buildCommands nimBin)}
runHook postBuild
'';
installPhase =
prevAttrs.installPhase or ''
runHook preInstall
${lib.strings.concatLines (installCommands nimBin)}
runHook postInstall
'';
nativeBuildInputs = (prevAttrs.nativeBuildInputs or [ ]) ++ [ nim ];
nimCfg =
prevAttrs.nimCfg or (buildNimCfg {
backend = prevAttrs.nimBackend or properties."nim:backend" or "c";
inherit (sbom) components;
});
passthru = {
inherit sbom properties nimBin;
};
};
applyOverrides =
prevAttrs:
builtins.foldl' (
prevAttrs:
{ name, ... }@component:
if (builtins.hasAttr name nimOverrides) then
prevAttrs // (nimOverrides.${name} component prevAttrs)
else
prevAttrs
) prevAttrs prevAttrs.passthru.sbom.components;
compose =
callerArg: sbom: finalAttrs:
let
callerAttrs = if builtins.isAttrs callerArg then callerArg else callerArg finalAttrs;
sbomAttrs = callerAttrs // (applySbom sbom callerAttrs);
overrideAttrs = sbomAttrs // (applyOverrides sbomAttrs);
in
overrideAttrs;
in
callerArg: sbomArg:
let
sbom = if builtins.isAttrs sbomArg then sbomArg else builtins.fromJSON (builtins.readFile sbomArg);
overrideSbom = f: stdenv.mkDerivation (compose callerArg (sbom // (f sbom)));
in
(stdenv.mkDerivation (compose callerArg sbom)) // { inherit overrideSbom; }

View file

@ -1,7 +1,10 @@
{ pkgs ? import <nixpkgs> { } }:
pkgs.buildNimPackage {
name = "syndicate_utils_linux";
lockFile = ./lock.json;
src = pkgs.lib.sources.cleanSource ./.;
}
{
pkgs ? import <nixpkgs> { },
}:
with pkgs;
let
buildNimSbom = pkgs.callPackage ./build-nim-sbom.nix { };
in
buildNimSbom (finalAttrs: {
src = if lib.inNixShell then null else lib.cleanSource ./.;
}) ./sbom.json

598
sbom.json Normal file
View file

@ -0,0 +1,598 @@
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"metadata": {
"component": {
"type": "application",
"bom-ref": "pkg:nim/syndev",
"name": "syndev",
"description": "Syndicate utilties for Linux.",
"version": "20240806",
"authors": [
{
"name": "Emery Hemingway"
}
],
"licenses": [
{
"license": {
"id": "Unlicense"
}
}
],
"properties": [
{
"name": "nim:skipExt",
"value": "nim"
},
{
"name": "nim:bin:uevent-dump",
"value": "uevent_dump"
},
{
"name": "nim:srcDir",
"value": "src"
},
{
"name": "nim:backend",
"value": "c"
}
]
}
},
"components": [
{
"type": "library",
"bom-ref": "pkg:nim/syndicate",
"name": "syndicate",
"version": "20240802",
"externalReferences": [
{
"url": "https://git.syndicate-lang.org/ehmry/syndicate-nim/archive/423d7e9944c7b29055ae44be6bdbba2c885fc94e.tar.gz",
"type": "source-distribution"
},
{
"url": "https://git.syndicate-lang.org/ehmry/syndicate-nim",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/zry30gjkabnyar9pf941nsmlq0pgh7lb-source"
},
{
"name": "nix:fod:rev",
"value": "423d7e9944c7b29055ae44be6bdbba2c885fc94e"
},
{
"name": "nix:fod:sha256",
"value": "16qkszw2gsbyg97i5jzz2lczhffkjfmh42h3h7v5k8rhf4l471r1"
},
{
"name": "nix:fod:url",
"value": "https://git.syndicate-lang.org/ehmry/syndicate-nim/archive/423d7e9944c7b29055ae44be6bdbba2c885fc94e.tar.gz"
},
{
"name": "nix:fod:ref",
"value": "20240802"
},
{
"name": "nix:fod:srcDir",
"value": "src"
}
]
},
{
"type": "library",
"bom-ref": "pkg:nim/nimcrypto",
"name": "nimcrypto",
"version": "485f7b3cfa83c1beecc0e31be0e964d697aa74d7",
"externalReferences": [
{
"url": "https://github.com/cheatfate/nimcrypto/archive/485f7b3cfa83c1beecc0e31be0e964d697aa74d7.tar.gz",
"type": "source-distribution"
},
{
"url": "https://github.com/cheatfate/nimcrypto",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/fkrcpp8lzj2yi21na79xm63xk0ggnqsp-source"
},
{
"name": "nix:fod:rev",
"value": "485f7b3cfa83c1beecc0e31be0e964d697aa74d7"
},
{
"name": "nix:fod:sha256",
"value": "1h3dzdbc9kacwpi10mj73yjglvn7kbizj1x8qc9099ax091cj5xn"
},
{
"name": "nix:fod:url",
"value": "https://github.com/cheatfate/nimcrypto/archive/485f7b3cfa83c1beecc0e31be0e964d697aa74d7.tar.gz"
}
]
},
{
"type": "library",
"bom-ref": "pkg:nim/preserves",
"name": "preserves",
"version": "20240802",
"externalReferences": [
{
"url": "https://git.syndicate-lang.org/ehmry/preserves-nim/archive/7ecc8cec3e119476a560d0c529b902a180852faa.tar.gz",
"type": "source-distribution"
},
{
"url": "https://git.syndicate-lang.org/ehmry/preserves-nim.git",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/3927dikh3a73gdmag890908kip1ali30-source"
},
{
"name": "nix:fod:rev",
"value": "7ecc8cec3e119476a560d0c529b902a180852faa"
},
{
"name": "nix:fod:sha256",
"value": "1151y09qbq3b7cn1rh39ln8kh22fq3vdic6vbsmdbc7vfyhnlyg0"
},
{
"name": "nix:fod:url",
"value": "https://git.syndicate-lang.org/ehmry/preserves-nim/archive/7ecc8cec3e119476a560d0c529b902a180852faa.tar.gz"
},
{
"name": "nix:fod:ref",
"value": "20240802"
},
{
"name": "nix:fod:srcDir",
"value": "src"
}
]
},
{
"type": "library",
"bom-ref": "pkg:nim/sys",
"name": "sys",
"version": "4ef3b624db86e331ba334e705c1aa235d55b05e1",
"externalReferences": [
{
"url": "https://github.com/ehmry/nim-sys/archive/4ef3b624db86e331ba334e705c1aa235d55b05e1.tar.gz",
"type": "source-distribution"
},
{
"url": "https://github.com/ehmry/nim-sys.git",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/syhxsjlsdqfap0hk4qp3s6kayk8cqknd-source"
},
{
"name": "nix:fod:rev",
"value": "4ef3b624db86e331ba334e705c1aa235d55b05e1"
},
{
"name": "nix:fod:sha256",
"value": "1q4qgw4an4mmmcbx48l6xk1jig1vc8p9cq9dbx39kpnb0890j32q"
},
{
"name": "nix:fod:url",
"value": "https://github.com/ehmry/nim-sys/archive/4ef3b624db86e331ba334e705c1aa235d55b05e1.tar.gz"
},
{
"name": "nix:fod:srcDir",
"value": "src"
}
]
},
{
"type": "library",
"bom-ref": "pkg:nim/taps",
"name": "taps",
"version": "20240405",
"externalReferences": [
{
"url": "https://git.sr.ht/~ehmry/nim_taps/archive/8c8572cd971d1283e6621006b310993c632da247.tar.gz",
"type": "source-distribution"
},
{
"url": "https://git.sr.ht/~ehmry/nim_taps",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/6y14ia52kr7jyaa0izx37mlablmq9s65-source"
},
{
"name": "nix:fod:rev",
"value": "8c8572cd971d1283e6621006b310993c632da247"
},
{
"name": "nix:fod:sha256",
"value": "1dp166bv9x773jmfqppg5i3v3rilgff013vb11yzwcid9l7s3iy8"
},
{
"name": "nix:fod:url",
"value": "https://git.sr.ht/~ehmry/nim_taps/archive/8c8572cd971d1283e6621006b310993c632da247.tar.gz"
},
{
"name": "nix:fod:ref",
"value": "20240405"
},
{
"name": "nix:fod:srcDir",
"value": "src"
}
]
},
{
"type": "library",
"bom-ref": "pkg:nim/solo5_dispatcher",
"name": "solo5_dispatcher",
"version": "20240522",
"externalReferences": [
{
"url": "https://git.sr.ht/~ehmry/solo5_dispatcher/archive/cc64ef99416b22b12e4a076d33de9e25a163e57d.tar.gz",
"type": "source-distribution"
},
{
"url": "https://git.sr.ht/~ehmry/solo5_dispatcher",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/4jj467pg4hs6warhksb8nsxn9ykz8c7c-source"
},
{
"name": "nix:fod:rev",
"value": "cc64ef99416b22b12e4a076d33de9e25a163e57d"
},
{
"name": "nix:fod:sha256",
"value": "1v9i9fqgx1g76yrmz2xwj9mxfwbjfpar6dsyygr68fv9031cqxq7"
},
{
"name": "nix:fod:url",
"value": "https://git.sr.ht/~ehmry/solo5_dispatcher/archive/cc64ef99416b22b12e4a076d33de9e25a163e57d.tar.gz"
},
{
"name": "nix:fod:ref",
"value": "20240522"
},
{
"name": "nix:fod:srcDir",
"value": "pkg"
}
]
},
{
"type": "library",
"bom-ref": "pkg:nim/npeg",
"name": "npeg",
"version": "1.2.2",
"externalReferences": [
{
"url": "https://github.com/zevv/npeg/archive/ec0cc6e64ea4c62d2aa382b176a4838474238f8d.tar.gz",
"type": "source-distribution"
},
{
"url": "https://github.com/zevv/npeg.git",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/xpn694ibgipj8xak3j4bky6b3k0vp7hh-source"
},
{
"name": "nix:fod:rev",
"value": "ec0cc6e64ea4c62d2aa382b176a4838474238f8d"
},
{
"name": "nix:fod:sha256",
"value": "1fi9ls3xl20bmv1ikillxywl96i9al6zmmxrbffx448gbrxs86kg"
},
{
"name": "nix:fod:url",
"value": "https://github.com/zevv/npeg/archive/ec0cc6e64ea4c62d2aa382b176a4838474238f8d.tar.gz"
},
{
"name": "nix:fod:ref",
"value": "1.2.2"
},
{
"name": "nix:fod:srcDir",
"value": "src"
}
]
},
{
"type": "library",
"bom-ref": "pkg:nim/nim-bigints",
"name": "bigints",
"version": "20231006",
"externalReferences": [
{
"url": "https://github.com/ehmry/nim-bigints/archive/86ea14d31eea9275e1408ca34e6bfe9c99989a96.tar.gz",
"type": "source-distribution"
},
{
"url": "https://github.com/ehmry/nim-bigints.git",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/jvrm392g8adfsgf36prgwkbyd7vh5jsw-source"
},
{
"name": "nix:fod:rev",
"value": "86ea14d31eea9275e1408ca34e6bfe9c99989a96"
},
{
"name": "nix:fod:sha256",
"value": "15pcpmnk1bnw3k8769rjzcpg00nahyrypwbxs88jnwr4aczp99j4"
},
{
"name": "nix:fod:url",
"value": "https://github.com/ehmry/nim-bigints/archive/86ea14d31eea9275e1408ca34e6bfe9c99989a96.tar.gz"
},
{
"name": "nix:fod:ref",
"value": "20231006"
},
{
"name": "nix:fod:srcDir",
"value": "src"
}
]
},
{
"type": "library",
"bom-ref": "pkg:nim/cps",
"name": "cps",
"version": "0.10.4",
"externalReferences": [
{
"url": "https://github.com/nim-works/cps/archive/2a4d771a715ba45cfba3a82fa625ae7ad6591c8b.tar.gz",
"type": "source-distribution"
},
{
"url": "https://github.com/nim-works/cps",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/m9vpcf3dq6z2h1xpi1vlw0ycxp91s5p7-source"
},
{
"name": "nix:fod:rev",
"value": "2a4d771a715ba45cfba3a82fa625ae7ad6591c8b"
},
{
"name": "nix:fod:sha256",
"value": "0c62k5wpq9z9mn8cd4rm8jjc4z0xmnak4piyj5dsfbyj6sbdw2bf"
},
{
"name": "nix:fod:url",
"value": "https://github.com/nim-works/cps/archive/2a4d771a715ba45cfba3a82fa625ae7ad6591c8b.tar.gz"
},
{
"name": "nix:fod:ref",
"value": "0.10.4"
}
]
},
{
"type": "library",
"bom-ref": "pkg:nim/stew",
"name": "stew",
"version": "3c91b8694e15137a81ec7db37c6c58194ec94a6a",
"externalReferences": [
{
"url": "https://github.com/status-im/nim-stew/archive/3c91b8694e15137a81ec7db37c6c58194ec94a6a.tar.gz",
"type": "source-distribution"
},
{
"url": "https://github.com/status-im/nim-stew",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/mqg8qzsbcc8xqabq2yzvlhvcyqypk72c-source"
},
{
"name": "nix:fod:rev",
"value": "3c91b8694e15137a81ec7db37c6c58194ec94a6a"
},
{
"name": "nix:fod:sha256",
"value": "17lfhfxp5nxvld78xa83p258y80ks5jb4n53152cdr57xk86y07w"
},
{
"name": "nix:fod:url",
"value": "https://github.com/status-im/nim-stew/archive/3c91b8694e15137a81ec7db37c6c58194ec94a6a.tar.gz"
}
]
},
{
"type": "library",
"bom-ref": "pkg:nim/getdns",
"name": "getdns",
"version": "20230806",
"externalReferences": [
{
"url": "https://git.sr.ht/~ehmry/getdns-nim/archive/e4ae0992ed7c5540e6d498f3074d06c8f454a0b6.tar.gz",
"type": "source-distribution"
},
{
"url": "https://git.sr.ht/~ehmry/getdns-nim",
"type": "vcs"
}
],
"properties": [
{
"name": "nix:fod:method",
"value": "fetchzip"
},
{
"name": "nix:fod:path",
"value": "/nix/store/j8i20k9aarzppg4p234449140nnnaycq-source"
},
{
"name": "nix:fod:rev",
"value": "e4ae0992ed7c5540e6d498f3074d06c8f454a0b6"
},
{
"name": "nix:fod:sha256",
"value": "1dp53gndr6d9s9601dd5ipkiq94j53hlx46mxv8gpr8nd98bqysg"
},
{
"name": "nix:fod:url",
"value": "https://git.sr.ht/~ehmry/getdns-nim/archive/e4ae0992ed7c5540e6d498f3074d06c8f454a0b6.tar.gz"
},
{
"name": "nix:fod:ref",
"value": "20230806"
},
{
"name": "nix:fod:srcDir",
"value": "src"
}
]
}
],
"dependencies": [
{
"ref": "pkg:nim/syndev",
"dependsOn": [
"pkg:nim/syndicate"
]
},
{
"ref": "pkg:nim/syndicate",
"dependsOn": [
"pkg:nim/nimcrypto",
"pkg:nim/preserves",
"pkg:nim/sys",
"pkg:nim/taps",
"pkg:nim/solo5_dispatcher"
]
},
{
"ref": "pkg:nim/nimcrypto",
"dependsOn": []
},
{
"ref": "pkg:nim/preserves",
"dependsOn": [
"pkg:nim/npeg",
"pkg:nim/nim-bigints"
]
},
{
"ref": "pkg:nim/sys",
"dependsOn": [
"pkg:nim/cps",
"pkg:nim/stew"
]
},
{
"ref": "pkg:nim/taps",
"dependsOn": [
"pkg:nim/getdns",
"pkg:nim/sys",
"pkg:nim/cps",
"pkg:nim/solo5_dispatcher"
]
},
{
"ref": "pkg:nim/solo5_dispatcher",
"dependsOn": [
"pkg:nim/cps"
]
},
{
"ref": "pkg:nim/npeg",
"dependsOn": []
},
{
"ref": "pkg:nim/nim-bigints",
"dependsOn": []
},
{
"ref": "pkg:nim/cps",
"dependsOn": []
},
{
"ref": "pkg:nim/stew",
"dependsOn": []
},
{
"ref": "pkg:nim/getdns",
"dependsOn": []
}
]
}

View file

@ -1,3 +0,0 @@
include_rules
: foreach *.nim | $(SYNDICATE_PROTOCOL) |> !nim_bin |> {bin}
: {bin} |> !assert_built |>

2
src/schema/Tupfile Normal file
View file

@ -0,0 +1,2 @@
include_rules
: foreach ../../*.prs |> !preserves-schema-nim |> %B.nim | $(PROJECT_DIR)/<schema>

19
src/schema/uevents.nim Normal file
View file

@ -0,0 +1,19 @@
import
preserves, std/tables
type
UventDumpStep* {.preservesRecord: "uevent-dump".} = object
Uevent* {.preservesRecord: "uvent".} = object
`subsystem`*: string
`devpath`*: string
`action`*: string
`attrs`*: Table[Symbol, string]
`seqnum`*: BiggestInt
proc `$`*(x: UventDumpStep | Uevent): string =
`$`(toPreserves(x))
proc encode*(x: UventDumpStep | Uevent): seq[byte] =
encode(toPreserves(x))

View file

@ -3,9 +3,13 @@
# *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
import
std/[nativesockets, options, os, parseutils, posix, sets],
pkg/sys/[handles, ioqueue, sockets],
pkg/preserves,
pkg/syndicate,
pkg/syndicate/protocols/[gatekeeper, sturdy],
./schema/uevents
var
AF_NETLINK {.importc, header: "sys/socket.h", nodecl.}: uint16
@ -38,7 +42,9 @@ proc openUeventSocket: SocketHandle =
close(result)
raise newException(IOError, "Netlink not supported")
proc openUeventSocketAsync: AsyncConn[sockets.Protocol.Unix] =
type Socket = AsyncConn[sockets.Protocol.Unix]
proc openUeventSocketAsync: Socket =
let fd = openUeventSocket()
var flags = fcntl(fd.cint, F_GETFL)
if flags < 0:
@ -46,9 +52,15 @@ proc openUeventSocketAsync: AsyncConn[sockets.Protocol.Unix] =
flags = flags or O_NONBLOCK
if fcntl(fd.cint, F_SETFL, flags) < 0:
raiseOSError(osLastError())
AsyncConn[sockets.Protocol.Unix] fd.SocketFD.initHandle.newAsyncSocket
fd.SocketFD.initHandle.newAsyncSocket.Socket
proc sendMessage(turn: var Turn; ds: Cap; buf: string; n: int) =
type
MessageRelay = ref object
facet: Facet
dataspace, attenuation: Cap
sock: Socket
proc sendMessage(relay: MessageRelay; turn: Turn; buf: string; n: int) =
var
msg = initRecord("uevent", toPreserves"", toPreserves"", toSymbol"", initDictionary(), 0.toPreserves)
key, val: string
@ -83,24 +95,45 @@ proc sendMessage(turn: var Turn; ds: Cap; buf: string; n: int) =
return
if msg.record[3].dict.len > 0:
cannonicalize(msg.record[3])
message(turn, ds, msg)
message(turn, relay.dataspace, msg)
msg.record[3].dict.setLen(0)
proc loop(facet: Facet; ds: Cap; sock: AsyncConn[sockets.Protocol.Unix]) {.asyncio.} =
proc loop(relay: MessageRelay; ) {.asyncio.} =
let buf = new string
buf[].setLen(16 shl 10)
while true:
let n = read(sock, buf)
if n < 1: stopActor(facet)
let n = relay.sock.read(buf)
if n < 1: stopActor(relay.facet)
else:
proc act(turn: var Turn) =
sendMessage(turn, ds, buf[], n)
run(facet, act)
proc act(turn: Turn) =
relay.sendMessage(turn, buf[], n)
relay.facet.run(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)
proc observeOnly: Caveat =
"""<reject <not <rec Observe [<_> <_>]>>>""".parsePreserves.preservesTo(Caveat).get
proc newMessageRelay(turn: Turn): MessageRelay =
new result
result.sock = openUeventSocketAsync()
result.facet = turn.facet
result.dataspace = turn.newDataspace()
result.attenuation = result.dataspace.attenuate observeOnly()
discard trampoline:
whelp result.loop()
# Start reading from the socket.
proc spawnUdevDumpActor*(turn: Turn; gatekeeper: Cap): Actor {.discardable.} =
during(turn, gatekeeper, Resolve?:{ 0: UventDumpStep.matchType }) do:
# At least one subscriber asserted.
let relay = turn.newMessageRelay()
during(turn, gatekeeper, Resolve?:{ 0: UventDumpStep.matchType, 1: grab() }) do (observer: Cap):
publish(turn, observer, ResolvedAccepted(responderSession: relay.attenuation))
do:
relay.sock.close()
# All subscribers retracted.
when isMainModule:
import syndicate/relays
runActor("main") do (turn: Turn):
resolveEnvironment(turn) do (turn: Turn; gatekeeper: Cap):
spawnUdevDumpActor(turn, gatekeeper)

View file

@ -1,13 +1,61 @@
# Package
# Emulate Nimble from CycloneDX data at sbom.json.
version = "20240315"
author = "Emery Hemingway"
description = "Syndicate utilties for Linux."
license = "Unlicense"
srcDir = "src"
bin = @["uevent_dump"]
import std/json
proc lookupComponent(sbom: JsonNode; bomRef: string): JsonNode =
for c in sbom{"components"}.getElems.items:
if c{"bom-ref"}.getStr == bomRef:
return c
result = newJNull()
# Dependencies
let
sbom = (getPkgDir() & "/sbom.json").readFile.parseJson
comp = sbom{"metadata", "component"}
bomRef = comp{"bom-ref"}.getStr
requires "nim >= 1.6.12", "syndicate >= 20240208", "https://github.com/ehmry/nim-sys.git#b974e1a4ca6ae7d89fc9e7b3714b1e7daf6f33e5", "https://github.com/nim-works/cps"
version = comp{"version"}.getStr
author = comp{"authors"}[0]{"name"}.getStr
description = comp{"description"}.getStr
license = comp{"licenses"}[0]{"license", "id"}.getStr
for prop in comp{"properties"}.getElems.items:
let (key, val) = (prop{"name"}.getStr, prop{"value"}.getStr)
case key
of "nim:skipDirs:":
add(skipDirs, val)
of "nim:skipFiles:":
add(skipFiles, val)
of "nim:skipExt":
add(skipExt, val)
of "nim:installDirs":
add(installDirs, val)
of "nim:installFiles":
add(installFiles, val)
of "nim:installExt":
add(installExt, val)
of "nim:binDir":
add(binDir, val)
of "nim:srcDir":
add(srcDir, val)
of "nim:backend":
add(backend, val)
else:
if key.startsWith "nim:bin:":
namedBin[key[8..key.high]] = val
for depend in sbom{"dependencies"}.items:
if depend{"ref"}.getStr == bomRef:
for depRef in depend{"dependsOn"}.items:
let dep = sbom.lookupComponent(depRef.getStr)
var spec = dep{"name"}.getStr
for extRef in dep{"externalReferences"}.elems:
if extRef{"type"}.getStr == "vcs":
spec = extRef{"url"}.getStr
break
let ver = dep{"version"}.getStr
if ver != "":
if ver.allCharsInSet {'0'..'9', '.'}: spec.add " == "
else: spec.add '#'
spec.add ver
requires spec
break

View file

@ -1,3 +0,0 @@
version 1.
Uevent = <uvent @subsystem string @devpath string @action string @attrs {symbol: string ...:...} @seqnum int> .

8
uevents.prs Normal file
View file

@ -0,0 +1,8 @@
version 1.
# Message type.
Uevent = <uvent @subsystem string @devpath string @action string @attrs {symbol: string ...:...} @seqnum int> .
# Gatekeeper step for subscribing to uvent messages.
# Stepping with <uevent-dump { }> is also fine.
UventDumpStep = <uevent-dump> .