diff --git a/README.org b/README.org index e6a623f..54ca0d8 100644 --- a/README.org +++ b/README.org @@ -426,6 +426,14 @@ All files you want to link or bind to persistent storage. See [[#files][the NixOS module files section]] for more details. +**** Overriding when persisted paths are mounted + + Paths are only mounted when the systemd target for its storage path is brought up. By default these targets are wanted by ~local-fs.target~, meaning that they will be started on boot. For control over when paths are mounted, the targets should be modified to change or remove their ~WantedBy~ lists. To disable automatically mounting the above example: + + #+begin_src nix + systemd.targets."home-files-home-bird".wantedBy = lib.mkForce [ ]; + #+end_src + ** Further reading The following blog posts provide more information on the concept of ephemeral roots: diff --git a/nixos.nix b/nixos.nix index e14737e..8e0088c 100644 --- a/nixos.nix +++ b/nixos.nix @@ -109,6 +109,9 @@ let user = "root"; group = "root"; }; + + getCleanHomeName = home: builtins.replaceStrings [ "/" ] [ "-" ] home; + getUnitTarget = home: if home != null then "home-files${getCleanHomeName home}.target" else "local-fs.target"; in { options = { @@ -234,33 +237,34 @@ in { systemd.services = let - mkPersistFileService = { filePath, persistentStoragePath, ... }@args: + mkPersistFileService = { filePath, persistentStoragePath, home, ... }@args: let targetFile = concatPaths [ persistentStoragePath filePath ]; mountPoint = escapeShellArg filePath; in { - "persist-${escapeSystemdPath targetFile}" = { - description = "Bind mount or link ${targetFile} to ${mountPoint}"; - wantedBy = [ "local-fs.target" ]; - before = [ "local-fs.target" ]; - path = [ pkgs.util-linux ]; - unitConfig.DefaultDependencies = false; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - ExecStart = mkPersistFile args; - ExecStop = pkgs.writeShellScript "unbindOrUnlink-${escapeSystemdPath targetFile}" '' - set -eu - if [[ -L ${mountPoint} ]]; then - rm ${mountPoint} - else - umount ${mountPoint} - rm ${mountPoint} - fi - ''; + "persist-${escapeSystemdPath targetFile}" = + { + description = "Bind mount or link ${targetFile} to ${mountPoint}"; + wantedBy = [ (getUnitTarget home) ]; + before = [ (getUnitTarget home) ]; + path = [ pkgs.util-linux ]; + unitConfig.DefaultDependencies = false; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = mkPersistFile args; + ExecStop = pkgs.writeShellScript "unbindOrUnlink-${escapeSystemdPath targetFile}" '' + set -eu + if [[ -L ${mountPoint} ]]; then + rm ${mountPoint} + else + umount ${mountPoint} + rm ${mountPoint} + fi + ''; + }; }; - }; }; in foldl' recursiveUpdate { } (map mkPersistFileService files); @@ -288,24 +292,37 @@ in systemd.mounts = let - mkBindMount = { dirPath, persistentStoragePath, hideMount, allowTrash, ... }: { - wantedBy = [ "local-fs.target" ]; - before = [ "local-fs.target" ]; - where = concatPaths [ "/" dirPath ]; - what = concatPaths [ persistentStoragePath dirPath ]; - unitConfig.DefaultDependencies = false; - type = "none"; - options = concatStringsSep "," ([ - "bind" - ] ++ optionals hideMount [ - "x-gvfs-hide" - ] ++ optionals allowTrash [ - "x-gvfs-trash" - ]); - }; + mkBindMount = { dirPath, persistentStoragePath, hideMount, allowTrash, home, ... }: + { + wantedBy = [ (getUnitTarget home) ]; + before = [ (getUnitTarget home) ]; + where = concatPaths [ "/" dirPath ]; + what = concatPaths [ persistentStoragePath dirPath ]; + unitConfig.DefaultDependencies = false; + type = "none"; + options = concatStringsSep "," ([ + "bind" + ] ++ optionals hideMount [ + "x-gvfs-hide" + ] ++ optionals allowTrash [ + "x-gvfs-trash" + ]); + }; in map mkBindMount directories; + systemd.targets = builtins.listToAttrs (builtins.map + (entry: { + name = "home-files${getCleanHomeName entry.home}"; + value = { + description = "Target for persisted directories and files under ${entry.home}"; + + # Depends on local-fs.target by default, but can be easily overridden + wantedBy = [ "local-fs.target" ]; + }; + }) + (builtins.filter (entry: entry.home != null) (files ++ directories))); + system.activationScripts = let # Script to create directories in persistent and ephemeral