summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2026-04-04 16:50:09 -0600
committerAlejandro Soto <alejandro@34project.org>2026-04-06 18:44:08 -0600
commitf788e70bad24a8ee24813bc0096a4a8c9a7294a9 (patch)
tree5e109d47c12ae774c766be969b49a57d0bca2ff4
parentb3fb6115eb270dafec595e737c6b28bd93f463f4 (diff)
home/environ: vtmp: implement vtmp-restore
-rw-r--r--home/environ/vtmp.nix121
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]}"];
+ };
};
};