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 388071b6..9cfd6094 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 666feb5a..4b925c9c 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 fff1df35..9e09c61b 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 35486679..800c81e3 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 fe3b187d..a87a8ac1 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 15e6f9f6..02d69f59 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";