diff --git a/docs/network.adoc b/docs/network.adoc index 976ae878..60abd7de 100644 --- a/docs/network.adoc +++ b/docs/network.adoc @@ -40,6 +40,7 @@ bedroom-friend:: `10.1.1.82` bedroom-colour-strip:: `10.1.1.85` net_ac_9628:: `10.1.1.90` +ps2:: `10.1.1.96` pinecube:: `10.1.1.97` diff --git a/modules/nixos/tmpfiles.nix b/modules/nixos/tmpfiles.nix index 690d55ba..6ebd14c9 100644 --- a/modules/nixos/tmpfiles.nix +++ b/modules/nixos/tmpfiles.nix @@ -1,11 +1,13 @@ { config, lib, + inputs, pkgs, ... }: let + inherit (inputs.self.lib.lib) unmerged; inherit (lib.options) mkOption mkEnableOption; - inherit (lib.modules) mkIf mkMerge mkOptionDefault; + inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault; inherit (lib.strings) match concatStringsSep escapeShellArg optionalString; inherit (lib.attrsets) attrValues; inherit (lib.lists) filter; @@ -23,6 +25,8 @@ }; mkdirParent = mkEnableOption "mkdir"; bindReadOnly = mkEnableOption "mount -oro"; + relativeSymlink = mkEnableOption "ln -sr"; + noOverwrite = mkEnableOption "disable overwrite"; path = mkOption { type = path; default = name; @@ -55,6 +59,9 @@ rules = mkOption { type = listOf str; }; + mountSettings = mkOption { + type = unmerged.type; + }; }; setup = { script = mkOption { @@ -83,6 +90,7 @@ chown = "chown ${escapeShellArg config.owner}:${escapeShellArg config.group} ${escapeShellArg config.path}"; chmod = "chmod ${escapeShellArg config.mode} ${escapeShellArg config.path}"; parentFlag = optionalString config.mkdirParent "p"; + relativeFlag = optionalString config.relativeSymlink "r"; scriptCatch = " || EXITCODE=$?"; scriptFail = "EXITCODE=1"; setupScript = { @@ -99,27 +107,36 @@ fi ''; symlink = '' - if [[ ! -e ${escapeShellArg config.path} || -L ${escapeShellArg config.path} ]]; then - ln -sf ${escapeShellArg config.src} ${escapeShellArg config.path}${scriptCatch} - else + if [[ -e ${escapeShellArg config.path} && ! -L ${escapeShellArg config.path} ]]; then echo ${escapeShellArg config.path} exists but is not a symlink >&2 ${scriptFail} + else + if [[ ! -L ${escapeShellArg config.path} || -z ${escapeShellArg config.noOverwrite} ]]; then + ln -s${relativeFlag}fT ${escapeShellArg config.src} ${escapeShellArg config.path}${scriptCatch} + fi fi ''; link = '' if [[ -L ${escapeShellArg config.path} ]]; then rm -f ${escapeShellArg config.path} fi - ln -f ${escapeShellArg config.src} ${escapeShellArg config.path}${scriptCatch} + ln -fT ${escapeShellArg config.src} ${escapeShellArg config.path}${scriptCatch} ''; copy = '' - if [[ ! -e ${escapeShellArg config.path} || -f ${escapeShellArg config.path} ]]; then - cp -f ${escapeShellArg config.src} ${escapeShellArg config.path} && - ${chmod} && - ${chown}${scriptCatch} - else - echo ${escapeShellArg config.path} exists but is not a file >&2 + if [[ -d ${escapeShellArg config.src} ]]; then + echo TODO: copy directory to ${escapeShellArg config.path} >&2 ${scriptFail} + else + if [[ -L ${escapeShellArg config.path} ]] || [[ -e ${escapeShellArg config.path} && ! -f ${escapeShellArg config.path} ]]; then + echo ${escapeShellArg config.path} exists but is not a file >&2 + ${scriptFail} + else + if [[ ! -e ${escapeShellArg config.path} || -z ${escapeShellArg config.noOverwrite} ]]; then + cp -TPf ${escapeShellArg config.src} ${escapeShellArg config.path}${scriptCatch} + fi + ${chmod} && + ${chown}${scriptCatch} + fi fi ''; bind = '' @@ -152,6 +169,22 @@ systemdRule.${config.type} (mkIf enableAcls [ systemdAclRule ]) ]; + mountSettings = mkIf (config.type == "bind") { + enable = mkDefault config.enable; + type = mkDefault "none"; + options = mkMerge [ + "bind" + (mkIf config.bindReadOnly "ro") + ]; + what = mkDefault config.src; + where = mkDefault config.path; + wantedBy = [ + "tmpfiles.service" + ]; + after = mkDefault [ + "tmpfiles.service" + ]; + }; }; }; }; @@ -200,20 +233,7 @@ in { RemainAfterExit = mkOptionDefault true; }; }; - mounts = map (file: rec { - enable = file.enable; - type = "none"; - options = mkMerge [ - "bind" - (mkIf file.bindReadOnly "ro") - ]; - what = file.src; - where = file.path; - wantedBy = [ - "tmpfiles.service" - ]; - after = wantedBy; - }) bindFiles; + mounts = map (file: unmerged.merge file.systemd.mountSettings) bindFiles; }; }; } diff --git a/nixos/kyuuto/opl.nix b/nixos/kyuuto/opl.nix new file mode 100644 index 00000000..1dec7b2d --- /dev/null +++ b/nixos/kyuuto/opl.nix @@ -0,0 +1,100 @@ +{ + pkgs, + config, + lib, + ... +}: let + inherit (lib.options) mkOption mkEnableOption; + inherit (lib.modules) mkIf mkMerge mkDefault; + inherit (config) kyuuto; + cfg = kyuuto.opl; +in { + options.kyuuto.opl = with lib.types; { + enable = mkEnableOption "hosting" // { + default = config.services.samba.enable; + }; + user = mkOption { + type = str; + default = "opl"; + }; + rootDir = mkOption { + type = path; + default = kyuuto.mountDir + "/opl"; + }; + dvdDir = mkOption { + type = path; + default = cfg.rootDir + "/DVD"; + }; + gameLibraryDir = mkOption { + type = path; + default = kyuuto.gameLibraryDir + "/PS2"; + }; + }; + + config = { + services.samba = { + settings = mkIf cfg.enable { + "ntlm auth" = mkDefault "ntlmv1-permitted"; + "server min protocol" = mkDefault "NT1"; + }; + shares.opl = let + inherit (config.networking.access) cidrForNetwork; + localAddrs = cidrForNetwork.loopback.all ++ cidrForNetwork.local.all + ++ lib.optionals config.services.tailscale.enable cidrForNetwork.tail.all; + in mkIf cfg.enable { + comment = "Kyuuto Media OPL"; + path = cfg.rootDir; + writeable = true; + browseable = true; + public = false; + "valid users" = [ + cfg.user + "@kyuuto-peeps" + ]; + "strict sync" = false; + "keepalive" = 0; + "hosts allow" = localAddrs; + }; + }; + services.tmpfiles = let + setupFiles = { + ${cfg.rootDir} = { + owner = cfg.user; + group = mkDefault "kyuuto"; + mode = mkDefault "2775"; + }; + ${cfg.dvdDir} = { + type = mkDefault "directory"; + owner = mkDefault "admin"; + group = mkDefault "kyuuto"; + mode = mkDefault "2775"; + }; + "${cfg.rootDir}/games.bin" = { + type = "copy"; + owner = cfg.user; + group = mkDefault "kyuuto"; + mode = "0775"; + src = pkgs.writeText "empty" ""; + noOverwrite = true; + }; + "${cfg.gameLibraryDir}/games.bin" = { + type = "symlink"; + src = cfg.rootDir + "/games.bin"; + }; + }; + files = { + ${cfg.dvdDir} = { + type = "bind"; + src = cfg.gameLibraryDir; + bindReadOnly = true; + }; + }; + in { + enable = mkIf (kyuuto.setup || cfg.enable) true; + files = mkMerge [ + (mkIf kyuuto.setup setupFiles) + (mkIf cfg.enable files) + ]; + }; + }; +} diff --git a/nixos/kyuuto/samba.nix b/nixos/kyuuto/samba.nix index 4cc6b70d..2b67d257 100644 --- a/nixos/kyuuto/samba.nix +++ b/nixos/kyuuto/samba.nix @@ -26,20 +26,7 @@ in { enable = mkDefault true; path = mkDefault (kyuuto.mountDir + "/usershares"); }; - shares = mkIf cfg.enable { - opl = { - comment = "Kyuuto Media OPL"; - path = kyuuto.libraryDir + "/games/PS2"; - writeable = false; - browseable = false; - public = false; - "valid users" = [ - "opl" - "@kyuuto-peeps" - ]; - "read list" = [ "opl" ]; - "hosts allow" = localAddrs; - }; + shares = { kyuuto-transfer = { comment = "Kyuuto Media Transfer Area"; path = kyuuto.transferDir;