diff options
| author | Alejandro Soto <alejandro@34project.org> | 2026-04-04 16:50:09 -0600 |
|---|---|---|
| committer | Alejandro Soto <alejandro@34project.org> | 2026-04-06 18:44:08 -0600 |
| commit | f788e70bad24a8ee24813bc0096a4a8c9a7294a9 (patch) | |
| tree | 5e109d47c12ae774c766be969b49a57d0bca2ff4 | |
| parent | b3fb6115eb270dafec595e737c6b28bd93f463f4 (diff) | |
home/environ: vtmp: implement vtmp-restore
| -rw-r--r-- | home/environ/vtmp.nix | 121 |
1 files changed, 109 insertions, 12 deletions
diff --git a/home/environ/vtmp.nix b/home/environ/vtmp.nix index e15778d..7513f2d 100644 --- a/home/environ/vtmp.nix +++ b/home/environ/vtmp.nix @@ -7,7 +7,10 @@ with lib; let cfg = config.local.environ; - vtmp-sync = pkgs.writeShellScript "vtmp-sync" '' + prelude = pkgs.writeText "vtmp-prelude" '' + set -o errexit + set -o pipefail + if [ $# -ne 3 ]; then echo "usage: $0 <remote hostname> <local hostname> <boot id>" >&2 exit 1 @@ -15,8 +18,9 @@ with lib; let local="$2" remote="$1" - boot_id="$(echo "$3" | ${pkgs.coreutils}/bin/head -c8)" + boot_id="$(echo "$3" | head -c8)" + ssh="${lib.getExe pkgs.openssh} -o BatchMode=yes" rsync="${lib.getExe pkgs.rsync}" cd "$HOME/vtmp" @@ -27,16 +31,91 @@ with lib; let rsync_opts+=("--open-noatime") rsync_opts+=("--preallocate") rsync_opts+=("--max-size=1G") - rsync_opts+=("--rsh=${lib.getExe pkgs.openssh} -o BatchMode=yes") - rsync_opts+=("--log-file=$remote/.rsync.log") - rsync_opts+=("--filter=- /$local.$boot_id/") + rsync_opts+=("--rsh=$ssh") + rsync_opts+=("--log-file=.rsync-$remote.log") rsync_opts+=("--filter=- /$remote/") + rsync_opts+=("--filter=- /$remote") + ''; + + vtmp-restore = pkgs.writeShellScript "vtmp-restore" '' + source ${prelude} + + [ ! -L .restore ] || exit 0 + + parent="$($ssh -- "$remote" " \ + set -o errexit; \ + set -o pipefail; \ + \ + mkdir -p -- \"vtmp/$local/$boot_id\"; \ + ln -fsT -- ../.. \"vtmp/$local/$boot_id/$remote\"; \ + \ + last=\"\$(readlink -qe -- \"vtmp/$local/last\")\" || { echo \"$boot_id\"; exit 0; }; \ + if [ \"\$last\" != \"$boot_id\" -a ! -L \"vtmp/$local/$boot_id/.last\" ]; then \ + ln -fsT -- \"$remote/$local/\$last\" \"vtmp/$local/$boot_id/.last\"; \ + fi; \ + \ + parent=\"\$(realpath -qe --relative-to=\"vtmp/$local\" -- \"vtmp/$local/last/.save\")\" || \ + { echo \"$boot_id\"; exit 0; }; \ + \ + if [ \"vtmp/$local/$boot_id/.last\" -nt \"vtmp/$local/\$parent/.last\" ]; then \ + mv -T --exchange --no-copy \"vtmp/$local\"/{\"\$parent\",\"$boot_id\"}/.last; \ + fi; \ + \ + echo \"\$parent\"; \ + ")" + + if [ -z "$parent" ]; then + echo "$0: error: empty parent" >&2 + exit 1 + fi + + # Pull restored state from $remote + # Note that $parent can equal $boot_id if ~/vtmp got cleared after saving with no reboot + rsync_opts+=("--filter=- /.save") + rsync_opts+=("--filter=- /.restore") + $rsync "''${rsync_opts[@]}" -- "$remote:vtmp/$local/$parent/" ./ + + $ssh -- "$remote" " \ + set -o errexit; \ + set -o pipefail; \ + \ + touch -cr \"vtmp/$local/$parent\" \"vtmp/$local/$boot_id\"; \ + if [ \"$parent\" != \"$boot_id\" ]; then \ + ln -fsT -- \"$remote/$local/$parent\" \"vtmp/$local/$boot_id/.save\"; \ + fi; \ + \ + ln -fsT -- \"$boot_id\" \"vtmp/$local/last\"; \ + \ + if [ \"$parent\" != \"$boot_id\" ]; then \ + rm -f \"vtmp/$local/$parent/.save\"; \ + \ + for link in .restore; do \ + if [ -L \"vtmp/$local/$parent/\$link\" ]; then \ + mv -T \"vtmp/$local\"/{\"$parent\",\"$boot_id\"}/\"\$link\"; \ + fi; \ + done; \ + \ + touch -c \"vtmp/$local/$parent\"; \ + mv -T --exchange --no-copy \"vtmp/$local\"/{\"$parent\",\"$boot_id\"}; \ + fi; \ + " + + [ "$parent" != "$boot_id" ] && target="$remote/$local/$parent" || target=. + ln -fsT -- "$target" .restore + ''; + + vtmp-sync = pkgs.writeShellScript "vtmp-sync" '' + source ${prelude} # Push to $remote from $local - "$rsync" "''${rsync_opts[@]}" -- ./ "$remote:vtmp/$local.$boot_id/" + rsync_opts+=("--delete") + $rsync "''${rsync_opts[@]}" -- ./ "$remote:vtmp/$local/$boot_id/" # Pull from $remote to $local - "$rsync" "''${rsync_opts[@]}" -- "$remote:vtmp/" "./$remote/" + rsync_opts+=("--filter=- /$local/$boot_id/") + $rsync "''${rsync_opts[@]}" -- "$remote:vtmp/" "./$remote/" + + ln -fsT ../.. "./$remote/$local/$boot_id" ''; in { options.local.environ = { @@ -77,13 +156,31 @@ in { }; }; - services.vtmp-sync = { - Unit = { - OnFailure = ["vtmp-sync-failure.target"]; + services = { + vtmp-restore = { + Unit = { + ConditionPathIsSymbolicLink = ["!%t/vtmp/.restore"]; + }; + + Service = { + Type = "oneshot"; + ExecStart = "${vtmp-restore} ${cfg.vtmpSyncHost} %l %b"; + Environment = ["PATH=${lib.makeBinPath [pkgs.coreutils]}"]; + }; }; - Service = { - ExecStart = "${vtmp-sync} ${cfg.vtmpSyncHost} %l %b"; + vtmp-sync = { + Unit = { + After = ["vtmp-restore.service"]; + Requires = ["vtmp-restore.service"]; + OnFailure = ["vtmp-sync-failure.target"]; + }; + + Service = { + Type = "oneshot"; + ExecStart = "${vtmp-sync} ${cfg.vtmpSyncHost} %l %b"; + Environment = ["PATH=${lib.makeBinPath [pkgs.coreutils]}"]; + }; }; }; |
