nix: configure sharefs via fileSystems
Some checks failed
Test / Create distribution (push) Successful in 43s
Test / Sandbox (push) Successful in 2m27s
Test / Hakurei (push) Successful in 3m24s
Test / ShareFS (push) Successful in 3m25s
Test / Hpkg (push) Successful in 4m7s
Test / Hakurei (race detector) (push) Successful in 5m33s
Test / Sandbox (race detector) (push) Successful in 4m36s
Test / Flake checks (push) Failing after 1m36s

Turns out this did not work because in the vm test harness, virtualisation.fileSystems completely and silently overrides fileSystems, causing its contents to not even be evaluated anymore. This is not documented as far as I can tell, and is not obvious by any stretch of the imagination. The current hack is cargo culted from nix-community/impermanence and hopefully lasts until this project fully replaces nix.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2025-12-27 22:52:12 +09:00
parent e7982b4ee9
commit 2a5e0e1b50
6 changed files with 135 additions and 40 deletions

View File

@@ -17,9 +17,6 @@
environment = {
# For benchmarking sharefs:
systemPackages = [ pkgs.fsmark ];
# For sharefs option checks without adding to PATH:
etc.sharefs.source = "${config.environment.hakurei.package}/libexec/sharefs";
};
virtualisation = {

View File

@@ -2,14 +2,14 @@ start_all()
machine.wait_for_unit("multi-user.target")
# To check sharefs version:
print(machine.succeed("/etc/sharefs -V"))
print(machine.succeed("sharefs -V"))
# Make sure sharefs did not terminate:
machine.wait_for_unit("sharefs.service")
# Make sure sharefs started:
machine.wait_for_unit("sdcard.mount")
machine.succeed("mkdir /mnt")
def check_bad_opts_output(opts, want, source="/etc", privileged=False):
output = machine.fail(("" if privileged else "sudo -u alice -i ") + f"/etc/sharefs -f -o source={source},{opts} /mnt 2>&1")
output = machine.fail(("" if privileged else "sudo -u alice -i ") + f"sharefs -f -o source={source},{opts} /mnt 2>&1")
if output != want:
raise Exception(f"unexpected output: {output}")
@@ -40,7 +40,7 @@ machine.succeed("rmdir /mnt")
# Unprivileged mount/unmount:
machine.succeed("sudo -u alice -i mkdir /home/alice/{sdcard,persistent}")
machine.succeed("sudo -u alice -i /etc/sharefs -o source=/home/alice/persistent /home/alice/sdcard")
machine.succeed("sudo -u alice -i sharefs -o source=/home/alice/persistent /home/alice/sdcard")
machine.succeed("sudo -u alice -i touch /home/alice/sdcard/check")
machine.succeed("sudo -u alice -i umount /home/alice/sdcard")
machine.succeed("sudo -u alice -i rm /home/alice/persistent/check")

View File

@@ -138,6 +138,10 @@
;
};
hsu = pkgs.callPackage ./cmd/hsu/package.nix { inherit (self.packages.${system}) hakurei; };
sharefs = pkgs.linkFarm "sharefs" {
"bin/sharefs" = "${hakurei}/libexec/sharefs";
"bin/mount.fuse.sharefs" = "${hakurei}/libexec/sharefs";
};
dist = pkgs.runCommand "${hakurei.name}-dist" { buildInputs = hakurei.targetPkgs ++ [ pkgs.pkgsStatic.musl ]; } ''
# go requires XDG_CACHE_HOME for the build cache

View File

@@ -24,11 +24,38 @@ let
getsubuid = userid: appid: userid * 100000 + 10000 + appid;
getsubname = userid: appid: "u${toString userid}_a${toString appid}";
getsubhome = userid: appid: "${cfg.stateDir}/u${toString userid}/a${toString appid}";
mountpoints = {
${cfg.sharefs.name} = mkIf (cfg.sharefs.source != null) {
depends = [ cfg.sharefs.source ];
device = "sharefs";
fsType = "fuse.sharefs";
noCheck = true;
options = [
"rw"
"noexec"
"nosuid"
"nodev"
"noatime"
"allow_other"
"mkdir"
"source=${cfg.sharefs.source}"
"setuid=${toString config.users.users.${cfg.sharefs.user}.uid}"
"setgid=${toString config.users.groups.${cfg.sharefs.group}.gid}"
];
};
};
in
{
imports = [ (import ./options.nix packages) ];
options = {
# Forward declare a dummy option for VM filesystems since the real one won't exist
# unless the VM module is actually imported.
virtualisation.fileSystems = lib.mkOption { };
};
config = mkIf cfg.enable {
assertions = [
(
@@ -66,38 +93,9 @@ in
) "" cfg.users;
};
systemd.services = {
sharefs = mkIf (cfg.sharefs.source != null) {
unitConfig.RequiresMountsFor = cfg.sharefs.source;
serviceConfig = {
NoNewPrivileges = true;
};
script = ''
${pkgs.coreutils}/bin/install -dm0 ${cfg.sharefs.name}
exec ${cfg.package}/libexec/sharefs -f \
-o ${
lib.join "," [
"noexec"
"nosuid"
"nodev"
"noatime"
"auto_unmount"
"allow_other"
"setuid=$(id -u ${cfg.sharefs.user})"
"setgid=$(id -g ${cfg.sharefs.group})"
"source=${cfg.sharefs.source}"
"mkdir"
]
} ${cfg.sharefs.name}
'';
# do not unmount on configuration changes
restartIfChanged = false;
wantedBy = [ "multi-user.target" ];
};
};
environment.systemPackages = optional (cfg.sharefs.source != null) cfg.sharefs.package;
fileSystems = mountpoints;
virtualisation.fileSystems = mountpoints;
home-manager =
let

View File

@@ -809,6 +809,96 @@ package
## environment\.hakurei\.sharefs\.package
The sharefs package to use\.
*Type:*
package
*Default:*
` <derivation sharefs> `
## environment\.hakurei\.sharefs\.group
Name of the group to run the sharefs daemon as\.
*Type:*
string
*Default:*
` "sharefs" `
## environment\.hakurei\.sharefs\.name
Host path to mount sharefs on\.
*Type:*
string
*Default:*
` "/sdcard" `
## environment\.hakurei\.sharefs\.source
Writable backing directory\. Setting this to null disables sharefs\.
*Type:*
null or string
*Default:*
` null `
## environment\.hakurei\.sharefs\.user
Name of the user to run the sharefs daemon as\.
*Type:*
string
*Default:*
` "sharefs" `
## environment\.hakurei\.shell

View File

@@ -41,6 +41,12 @@ in
};
sharefs = {
package = mkOption {
type = types.package;
default = packages.${pkgs.stdenv.hostPlatform.system}.sharefs;
description = "The sharefs package to use.";
};
user = mkOption {
type = types.str;
default = "sharefs";