From 1e7f9def3b0d74dccb9f3876ba3ba7666641aa52 Mon Sep 17 00:00:00 2001 From: magic_rb Date: Sat, 21 Oct 2023 17:34:58 +0200 Subject: [PATCH] Allow for symlinking files Signed-off-by: magic_rb --- mount-file.bash | 36 +++++++++++++++++++++++------------- nixos.nix | 26 +++++++++++++++++++++----- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/mount-file.bash b/mount-file.bash index 6202d07..09d3297 100755 --- a/mount-file.bash +++ b/mount-file.bash @@ -10,7 +10,7 @@ shopt -s inherit_errexit # Inherit the errexit option status in subshells. trap 'echo Error when executing ${BASH_COMMAND} at line ${LINENO}! >&2' ERR # Get inputs from command line arguments -if [[ "$#" != 3 ]]; then +if [[ "$#" != 4 ]]; then echo "Error: 'mount-file.bash' requires *three* args." >&2 exit 1 fi @@ -18,6 +18,7 @@ fi mountPoint="$1" targetFile="$2" debug="$3" +method="$4" trace() { if (( "$debug" )); then @@ -28,16 +29,25 @@ if (( "$debug" )); then set -o xtrace fi -if [[ -L "$mountPoint" && $(readlink -f "$mountPoint") == "$targetFile" ]]; then - trace "$mountPoint already links to $targetFile, ignoring" -elif mount | grep -F "$mountPoint"' ' >/dev/null && ! mount | grep -F "$mountPoint"/ >/dev/null; then - trace "mount already exists at $mountPoint, ignoring" -elif [[ -e "$mountPoint" ]]; then - echo "A file already exists at $mountPoint!" >&2 - exit 1 -elif [[ -e "$targetFile" ]]; then - touch "$mountPoint" - mount -o bind "$targetFile" "$mountPoint" -else - ln -s "$targetFile" "$mountPoint" +if [[ "$method" == "bind" ]]; then + if [[ -L "$mountPoint" && $(readlink -f "$mountPoint") == "$targetFile" ]]; then + trace "$mountPoint already links to $targetFile, ignoring" + elif mount | grep -F "$mountPoint"' ' >/dev/null && ! mount | grep -F "$mountPoint"/ >/dev/null; then + trace "mount already exists at $mountPoint, ignoring" + elif [[ -e "$mountPoint" ]]; then + echo "A file already exists at $mountPoint!" >&2 + exit 1 + elif [[ -e "$targetFile" ]]; then + touch "$mountPoint" + mount -o bind "$targetFile" "$mountPoint" + else + ln -s "$targetFile" "$mountPoint" + fi +elif [[ "$method" == "symlink" ]]; then + if [[ -e "$mountPoint" ]] && ! [[ -L "$mountPoint" ]]; then + echo "symlink requested, but something else than symlink is present at $mountPoint" + exit 1 + else + ln -sf "$targetFile" "$mountPoint" + fi fi diff --git a/nixos.nix b/nixos.nix index b7a104f..bed7962 100644 --- a/nixos.nix +++ b/nixos.nix @@ -40,6 +40,11 @@ let parentsOf ; + isSymlink = entry: + entry.method == "symlink"; + isBind = entry: + entry.method == "bind"; + cfg = config.environment.persistence; users = config.users.users; allPersistentStoragePaths = { directories = [ ]; files = [ ]; users = [ ]; } @@ -64,7 +69,7 @@ let # Create all fileSystems bind mount entries for a specific # persistent storage path. - bindMounts = listToAttrs (map mkBindMountNameValuePair directories); + bindMounts = listToAttrs (map mkBindMountNameValuePair (filter isBind directories)); in { options = { @@ -83,6 +88,7 @@ in either str coercedTo + enum ; in attrsOf ( @@ -96,6 +102,13 @@ in }; commonOpts = { options = { + method = mkOption { + type = enum [ "bind" "symlink" ]; + default = "bind"; + description = '' + Whether to use a bind mount or a plain symlink to persist this. + ''; + }; persistentStoragePath = mkOption { type = path; default = cfg.${name}.persistentStoragePath; @@ -477,7 +490,7 @@ in config = { systemd.services = let - mkPersistFileService = { filePath, persistentStoragePath, enableDebugging, ... }: + mkPersistFileService = { filePath, persistentStoragePath, enableDebugging, method, ... }: let targetFile = escapeShellArg (concatPaths [ persistentStoragePath filePath ]); mountPoint = escapeShellArg filePath; @@ -492,7 +505,7 @@ in serviceConfig = { Type = "oneshot"; RemainAfterExit = true; - ExecStart = "${mountFile} ${mountPoint} ${targetFile} ${escapeShellArg enableDebugging}"; + ExecStart = "${mountFile} ${mountPoint} ${targetFile} ${escapeShellArg enableDebugging} ${escapeShellArg method}"; ExecStop = pkgs.writeShellScript "unbindOrUnlink-${sanitizeName targetFile}" '' set -eu if [[ -L ${mountPoint} ]]; then @@ -505,8 +518,10 @@ in }; }; }; + mkPersistDirectoryService = { dirPath, ... }@args: + mkPersistFileService (args // { filePath = dirPath; }); in - foldl' recursiveUpdate { } (map mkPersistFileService files); + foldl' recursiveUpdate { } ((map mkPersistFileService files) ++ (map mkPersistDirectoryService (filter isSymlink directories))); fileSystems = bindMounts; # So the mounts still make it into a VM built from `system.build.vm` @@ -639,7 +654,7 @@ in exit $_status ''; - mkPersistFile = { filePath, persistentStoragePath, enableDebugging, ... }: + mkPersistFile = { filePath, persistentStoragePath, enableDebugging, method, ... }: let mountPoint = filePath; targetFile = concatPaths [ persistentStoragePath filePath ]; @@ -647,6 +662,7 @@ in mountPoint targetFile enableDebugging + method ]; in ''