fix s6 service ordering: unl0kr -> (wait for mount) -> sway
note that the systemd-aware mount never completes -- it's stuck in 'activating' forever. that's the next challenge
This commit is contained in:
@@ -32,8 +32,6 @@ in
|
||||
wheelNeedsPassword = false;
|
||||
};
|
||||
|
||||
security.pam.mount.enable = true;
|
||||
|
||||
system.activationScripts.makeEtcShadowSandboxable = {
|
||||
deps = [ "users" ];
|
||||
text = ''
|
||||
|
@@ -5,6 +5,61 @@ let
|
||||
persist-base = "/nix/persist";
|
||||
origin = config.sane.persist.stores."private".origin;
|
||||
backing = sane-lib.path.concat [ persist-base "private" ];
|
||||
|
||||
gocryptfs-private = pkgs.writeShellApplication {
|
||||
name = "mount.fuse.gocryptfs-private";
|
||||
runtimeInputs = with pkgs; [
|
||||
coreutils-full
|
||||
gocryptfs
|
||||
inotify-tools
|
||||
];
|
||||
text = ''
|
||||
# backing=$1
|
||||
# facing=$2
|
||||
mountArgs=("$@")
|
||||
passdir=/run/gocryptfs
|
||||
passfile="$passdir/private.key"
|
||||
|
||||
waitForPassfileOnce() {
|
||||
local timeout=$1
|
||||
if [ -f "$passfile" ]; then
|
||||
return 0
|
||||
else
|
||||
# wait for some file to be created inside the directory.
|
||||
# inotifywait returns 0 if the file was created. 1 or 2 if timeout was hit or it was interrupted by a different event.
|
||||
inotifywait --timeout "$timeout" --event create "$passdir"
|
||||
return 1 #< maybe it was created; we'll pick that up immediately, on next check
|
||||
fi
|
||||
}
|
||||
waitForPassfile() {
|
||||
# there's a race condition between testing the path and starting `inotifywait`.
|
||||
# therefore, use a retry loop. exponential backoff to decrease the impact of the race condition,
|
||||
# especially near the start of boot to allow for quick reboots even if/when i hit the race.
|
||||
for timeout in 4 4 8 8 8 8 16 16 16 16 16 16 16 16; do
|
||||
if waitForPassfileOnce "$timeout"; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
while true; do
|
||||
if waitForPassfileOnce 30; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
}
|
||||
tryOpenStore() {
|
||||
# try to open the store (blocking), if it fails, then delete the passfile because the user probably entered the wrong password
|
||||
echo "mounting with ''${mountArgs[*]}"
|
||||
gocryptfs -fg "''${mountArgs[@]}"
|
||||
rc=$?
|
||||
# should only return if the mount errored -- probably because of a password failure!
|
||||
rm -f "$passfile"
|
||||
return "$rc"
|
||||
}
|
||||
|
||||
waitForPassfile
|
||||
tryOpenStore
|
||||
'';
|
||||
};
|
||||
in
|
||||
lib.mkIf config.sane.persist.enable
|
||||
{
|
||||
@@ -28,7 +83,7 @@ lib.mkIf config.sane.persist.enable
|
||||
|
||||
fileSystems."${origin}" = {
|
||||
device = backing;
|
||||
fsType = "fuse.gocryptfs";
|
||||
fsType = "fuse.gocryptfs-private";
|
||||
options = [
|
||||
"noauto" # don't try to mount, until the user logs in!
|
||||
"nofail"
|
||||
@@ -39,50 +94,22 @@ lib.mkIf config.sane.persist.enable
|
||||
# "quiet"
|
||||
# "defaults" # "unknown flag: --defaults. Try 'gocryptfs -help'"
|
||||
"passfile=/run/gocryptfs/private.key"
|
||||
# options so that we can block for the password file *without* systemd killing us.
|
||||
# see: <https://bbs.archlinux.org/viewtopic.php?pid=1906174#p1906174>
|
||||
"x-systemd.mount-timeout=infinity"
|
||||
# "retry=10000"
|
||||
"fg"
|
||||
];
|
||||
noCheck = true;
|
||||
};
|
||||
|
||||
# let sane.fs know about the mount, and let systemd know to wait for the pass key before attempting a mount
|
||||
sane.fs."${origin}".mount = {
|
||||
depends = let
|
||||
keyfile = config.sane.fs."/run/gocryptfs/private.key";
|
||||
in [ keyfile.unit ];
|
||||
};
|
||||
# let sane.fs know about the mount
|
||||
sane.fs."${origin}".mount = {};
|
||||
# it also needs to know that the underlying device is an ordinary folder
|
||||
sane.fs."${backing}" = sane-lib.fs.wanted {
|
||||
dir.acl.user = config.sane.defaultUser;
|
||||
};
|
||||
|
||||
sane.fs."/run/gocryptfs/private.key".generated = let
|
||||
script = pkgs.writeShellScript "wait-for-gocryptfs-private" ''
|
||||
file="$1"
|
||||
dir=$(dirname "$file")
|
||||
|
||||
succeedOrWait() {
|
||||
if [ -f "$file" ]; then
|
||||
exit 0
|
||||
else
|
||||
# wait for some file to be created inside the directory.
|
||||
# inotifywait returns 0 if the file was created. 1 or 2 if timeout was hit or it was interrupted by a different event.
|
||||
${lib.getExe' pkgs.inotify-tools "inotifywait"} --timeout "$1" --event create "$dir" || true
|
||||
fi
|
||||
}
|
||||
# there's a race condition between testing the path and starting `inotifywait`.
|
||||
# therefore, use a retry loop. exponential backoff to decrease the impact of the race condition,
|
||||
# especially near the start of boot to allow for quick reboots even if/when i hit the race.
|
||||
for i in 4 4 8 8 16 16 16 16 16 16 16 16; do
|
||||
succeedOrWait "$i"
|
||||
done
|
||||
while true; do
|
||||
succeedOrWait 30
|
||||
done
|
||||
'';
|
||||
in {
|
||||
command = [ "${script}" "/run/gocryptfs/private.key" ];
|
||||
# no need for anyone else to be able to read the key
|
||||
acl.mode = "0400";
|
||||
};
|
||||
sane.fs."/run/gocryptfs" = sane-lib.fs.wanted {
|
||||
dir.acl.user = config.sane.defaultUser;
|
||||
dir.acl.mode = "0700";
|
||||
@@ -95,12 +122,13 @@ lib.mkIf config.sane.persist.enable
|
||||
"${originUnit}".wantedBy = [ "local-fs.target" ];
|
||||
};
|
||||
|
||||
# TODO: could add this *specifically* to the .mount file for the encrypted fs?
|
||||
system.fsPackages = [ pkgs.gocryptfs ]; # fuse needs to find gocryptfs
|
||||
system.fsPackages = [ gocryptfs-private ];
|
||||
|
||||
sane.user.services.gocryptfs-private = {
|
||||
description = "wait for /mnt/persist/private to be mounted";
|
||||
startCommand = "${lib.getExe' pkgs.systemd "systemctl"} start mnt-persist-private.mount";
|
||||
# startCommand = "${lib.getExe' pkgs.systemd "systemctl"} start mnt-persist-private.mount";
|
||||
command = "sleep infinity";
|
||||
readiness.waitExists = [ "/mnt/persist/private/init" ];
|
||||
partOf = [ "private-storage" ];
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user