From 2a5e0e1b50bd36ebea353299303331dc83aabd6c Mon Sep 17 00:00:00 2001 From: Ophestra Date: Sat, 27 Dec 2025 22:52:12 +0900 Subject: [PATCH] nix: configure sharefs via fileSystems 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 --- cmd/sharefs/test/configuration.nix | 3 - cmd/sharefs/test/test.py | 10 ++-- flake.nix | 4 ++ nixos.nix | 62 ++++++++++---------- options.md | 90 ++++++++++++++++++++++++++++++ options.nix | 6 ++ 6 files changed, 135 insertions(+), 40 deletions(-) diff --git a/cmd/sharefs/test/configuration.nix b/cmd/sharefs/test/configuration.nix index 388071b..9cfd609 100644 --- a/cmd/sharefs/test/configuration.nix +++ b/cmd/sharefs/test/configuration.nix @@ -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 = { diff --git a/cmd/sharefs/test/test.py b/cmd/sharefs/test/test.py index 666feb5..4b925c9 100644 --- a/cmd/sharefs/test/test.py +++ b/cmd/sharefs/test/test.py @@ -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") diff --git a/flake.nix b/flake.nix index fff1df3..9e09c61 100644 --- a/flake.nix +++ b/flake.nix @@ -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 diff --git a/nixos.nix b/nixos.nix index 3548667..800c81e 100644 --- a/nixos.nix +++ b/nixos.nix @@ -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 diff --git a/options.md b/options.md index fe3b187..a87a8ac 100644 --- a/options.md +++ b/options.md @@ -809,6 +809,96 @@ package +## environment\.hakurei\.sharefs\.package + + + +The sharefs package to use\. + + + +*Type:* +package + + + +*Default:* +` ` + + + +## 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 diff --git a/options.nix b/options.nix index 15e6f9f..02d69f5 100644 --- a/options.nix +++ b/options.nix @@ -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";