Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.org
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
89 changes: 53 additions & 36 deletions nixos.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down