Pure Erlang implementation of 9p2000 protocol
filesystem fs 9p2000 erlang 9p

Add `kamid` to packages in dev shell to test 9p implementation

To test against existing implementation I wanted some existing tool that
can be used to access 9p server. Kamid has `kamiftp` tool that is
FTP-like client for 9p servers. It needs some patches to work on macOS
so I add these changes in Nix derivation.

Unfortunately this will not work for client tests, but it is way easier
to find simple 9p server than it is to find simple 9p client for some
reason.

hauleth.dev 77c22caf 76e08ab8

verified
+122 -1
+17
flake.lock
··· 159 159 "type": "github" 160 160 } 161 161 }, 162 + "kamid": { 163 + "flake": false, 164 + "locked": { 165 + "lastModified": 1730762973, 166 + "narHash": "sha256-FQA/nfc3/WqzN1FY5pBOxK2coc1Tw+hn9H4NvF7oCAU=", 167 + "owner": "omar-polo", 168 + "repo": "kamid", 169 + "rev": "48e3b41db1a35f09e072985a9f238ca202999247", 170 + "type": "github" 171 + }, 172 + "original": { 173 + "owner": "omar-polo", 174 + "repo": "kamid", 175 + "type": "github" 176 + } 177 + }, 162 178 "nix": { 163 179 "inputs": { 164 180 "flake-compat": [ ··· 250 266 "inputs": { 251 267 "devenv": "devenv", 252 268 "flake-parts": "flake-parts_2", 269 + "kamid": "kamid", 253 270 "nixpkgs": "nixpkgs_2", 254 271 "systems": "systems" 255 272 }
+13 -1
flake.nix
··· 9 9 inputs.flake-parts.url = "github:hercules-ci/flake-parts"; 10 10 inputs.devenv.url = "github:cachix/devenv"; 11 11 inputs.systems.url = "github:nix-systems/default"; 12 + inputs.kamid = { 13 + url = "github:omar-polo/kamid"; 14 + flake = false; 15 + }; 12 16 13 17 outputs = {flake-parts, ...} @ inputs: 14 18 flake-parts.lib.mkFlake {inherit inputs;} { ··· 18 22 19 23 systems = import inputs.systems; 20 24 21 - perSystem = {pkgs, ...}: { 25 + perSystem = {pkgs, ...}: let 26 + kamid = pkgs.callPackage ./nix/kamid { inherit inputs; }; 27 + in { 22 28 formatter = pkgs.alejandra; 23 29 30 + packages = { 31 + inherit kamid; 32 + }; 33 + 24 34 devenv.shells.default = { 25 35 languages.erlang.enable = true; 36 + 37 + packages = [ kamid ]; 26 38 }; 27 39 }; 28 40 };
+33
nix/kamid/default.nix
··· 1 + # SPDX-FileCopyrightText: 2026 Łukasz Niemier <~@hauleth.dev> 2 + # 3 + # SPDX-License-Identifier: Apache-2.0 4 + 5 + { 6 + inputs, 7 + 8 + kamid, 9 + autoreconfHook, 10 + pkg-config, 11 + bison, 12 + stdenv, 13 + 14 + lib 15 + }: 16 + 17 + kamid.overrideAttrs (old: { 18 + version = "git"; 19 + 20 + src = inputs.kamid; 21 + 22 + nativeBuildInputs = old.nativeBuildInputs ++ [ 23 + autoreconfHook 24 + pkg-config 25 + bison 26 + ]; 27 + 28 + patches = lib.optionals stdenv.isDarwin [ ./macos.patch ]; 29 + 30 + meta.package.platforms = old.meta.package.platforms ++ [ 31 + "aarch64-darwin" 32 + ]; 33 + })
+56
nix/kamid/macos.patch
··· 1 + diff --git i/compat.h w/compat.h 2 + index 2819b0e..349865e 100644 3 + --- i/compat.h 4 + +++ w/compat.h 5 + @@ -193,4 +193,7 @@ long long strtonum(const char *, long long, long long, const char **); 6 + # include "compat/vis.h" 7 + #endif 8 + 9 + +#define SOCK_CLOEXEC 0 10 + +#define SOCK_NONBLOCK 0 11 + + 12 + #endif /* COMPAT_H */ 13 + diff --git i/kamid/client.c w/kamid/client.c 14 + index 33e0206..063c698 100644 15 + --- i/kamid/client.c 16 + +++ w/kamid/client.c 17 + @@ -418,7 +418,7 @@ qid_update_from_sb(struct qid *qid, struct stat *sb) 18 + * Theoretically (and hopefully!) this should be a 64 bit 19 + * number. Unfortunately, 9P uses 32 bit timestamps. 20 + */ 21 + - qid->vers = sb->st_mtim.tv_sec; 22 + + qid->vers = sb->st_mtime; 23 + 24 + if (S_ISREG(sb->st_mode)) 25 + qid->type = QTFILE; 26 + @@ -1477,8 +1477,8 @@ serialize_stat(const char *fname, struct stat *sb, struct evbuffer *evb) 27 + np_write32(evb, sb->st_dev); /* dev[4] */ 28 + np_qid(evb, &qid); /* qid[13] */ 29 + np_write32(evb, mode); /* mode[4] */ 30 + - np_write32(evb, sb->st_atim.tv_sec); /* atime[4] */ 31 + - np_write32(evb, sb->st_mtim.tv_sec); /* mtime[4] */ 32 + + np_write32(evb, sb->st_atime); /* atime[4] */ 33 + + np_write32(evb, sb->st_mtime); /* mtime[4] */ 34 + 35 + /* special case: directories have size 0 */ 36 + if (qid.type & QTDIR) 37 + diff --git i/kamid/control.c w/kamid/control.c 38 + index 9fef9a5..dd44435 100644 39 + --- i/kamid/control.c 40 + +++ w/kamid/control.c 41 + @@ -67,12 +67,14 @@ control_init(const char *path) 42 + int fd; 43 + mode_t old_umask; 44 + 45 + - if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 46 + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 47 + 0)) == -1) { 48 + log_warn("%s: socket", __func__); 49 + return (-1); 50 + } 51 + 52 + + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK | O_CLOEXEC); 53 + + 54 + memset(&sun, 0, sizeof(sun)); 55 + sun.sun_family = AF_UNIX; 56 + strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
+3
nix/kamid/macos.patch.license
··· 1 + SPDX-FileCopyrightText: 2026 Łukasz Niemier <~@hauleth.dev> 2 + 3 + SPDX-License-Identifier: Apache-2.0