1 { config, lib, pkgs, utils, ... }:
5 bootFs = lib.filterAttrs (n: fs: (fs.fsType == "bcachefs") && (utils.fsNeededForBoot fs)) config.fileSystems;
10 printf "enter passphrase for $name: "
18 local uuid=$(echo -n $path | sed -e 's,UUID=\(.*\),\1,g')
20 printf "waiting for device to appear $path"
21 for try in $(seq 10); do
23 target=$(readlink -f $path)
27 target=$(blkid --uuid $uuid)
37 if [ $success == true ]; then
41 if bcachefs unlock -c $path > /dev/null 2> /dev/null; then # test for encryption
43 until bcachefs unlock $path 2> /dev/null; do # repeat until successfully unlocked
44 printf "unlocking failed!\n"
47 printf "unlocking successful.\n"
49 echo "Cannot unlock device $uuid with path $path" >&2
54 # we need only unlock one device manually, and cannot pass multiple at once
55 # remove this adaptation when bcachefs implements mounting by filesystem uuid
56 # also, implement automatic waiting for the constituent devices when that happens
57 # bcachefs does not support mounting devices with colons in the path, ergo we don't (see #49671)
58 firstDevice = fs: lib.head (lib.splitString ":" fs.device);
60 useClevis = fs: config.boot.initrd.clevis.enable && (lib.hasAttr (firstDevice fs) config.boot.initrd.clevis.devices);
62 openCommand = name: fs: if useClevis fs then ''
63 if clevis decrypt < /etc/clevis/${firstDevice fs}.jwe | bcachefs unlock ${firstDevice fs}
65 printf "unlocked ${name} using clevis\n"
67 printf "falling back to interactive unlocking...\n"
68 tryUnlock ${name} ${firstDevice fs}
71 tryUnlock ${name} ${firstDevice fs}
74 mkUnits = prefix: name: fs: let
75 mountUnit = "${utils.escapeSystemdPath (prefix + (lib.removeSuffix "/" fs.mountPoint))}.mount";
76 device = firstDevice fs;
77 deviceUnit = "${utils.escapeSystemdPath device}.device";
79 name = "unlock-bcachefs-${utils.escapeSystemdPath fs.mountPoint}";
81 description = "Unlock bcachefs for ${fs.mountPoint}";
82 requiredBy = [ mountUnit ];
83 after = [ deviceUnit ];
84 before = [ mountUnit "shutdown.target" ];
85 bindsTo = [ deviceUnit ];
86 conflicts = [ "shutdown.target" ];
87 unitConfig.DefaultDependencies = false;
90 ExecCondition = "${pkgs.bcachefs-tools}/bin/bcachefs unlock -c \"${device}\"";
91 Restart = "on-failure";
92 RestartMode = "direct";
93 # Ideally, this service would lock the key on stop.
94 # As is, RemainAfterExit doesn't accomplish anything.
95 RemainAfterExit = true;
98 unlock = ''${pkgs.bcachefs-tools}/bin/bcachefs unlock "${device}"'';
99 unlockInteractively = ''${config.boot.initrd.systemd.package}/bin/systemd-ask-password --timeout=0 "enter passphrase for ${name}" | exec ${unlock}'';
100 in if useClevis fs then ''
101 if ${config.boot.initrd.clevis.package}/bin/clevis decrypt < "/etc/clevis/${device}.jwe" | ${unlock}
103 printf "unlocked ${name} using clevis\n"
105 printf "falling back to interactive unlocking...\n"
106 ${unlockInteractively}
109 ${unlockInteractively}
117 kernel = config.boot.kernelPackages.kernel;
119 kernel.kernelAtLeast "6.7" || (
120 lib.elem (kernel.structuredExtraConfig.BCACHEFS_FS or null) [
123 (lib.kernel.option lib.kernel.yes)
128 message = "Linux 6.7-rc1 at minimum or a custom linux kernel with bcachefs support is required";
134 config = lib.mkIf (config.boot.supportedFilesystems.bcachefs or false) (lib.mkMerge [
137 # needed for systemd-remount-fs
138 system.fsPackages = [ pkgs.bcachefs-tools ];
139 # FIXME: Remove this line when the LTS (default) kernel is at least version 6.7
140 boot.kernelPackages = lib.mkDefault pkgs.linuxPackages_latest;
141 services.udev.packages = [ pkgs.bcachefs-tools ];
144 packages = [ pkgs.bcachefs-tools ];
145 services = lib.mapAttrs' (mkUnits "") (lib.filterAttrs (n: fs: (fs.fsType == "bcachefs") && (!utils.fsNeededForBoot fs)) config.fileSystems);
149 (lib.mkIf ((config.boot.initrd.supportedFilesystems.bcachefs or false) || (bootFs != {})) {
151 # chacha20 and poly1305 are required only for decryption attempts
152 boot.initrd.availableKernelModules = [ "bcachefs" "sha256" "chacha20" "poly1305" ];
153 boot.initrd.systemd.extraBin = {
154 # do we need this? boot/systemd.nix:566 & boot/systemd/initrd.nix:357
155 "bcachefs" = "${pkgs.bcachefs-tools}/bin/bcachefs";
156 "mount.bcachefs" = "${pkgs.bcachefs-tools}/bin/mount.bcachefs";
158 boot.initrd.extraUtilsCommands = lib.mkIf (!config.boot.initrd.systemd.enable) ''
159 copy_bin_and_libs ${pkgs.bcachefs-tools}/bin/bcachefs
160 copy_bin_and_libs ${pkgs.bcachefs-tools}/bin/mount.bcachefs
162 boot.initrd.extraUtilsCommandsTest = lib.mkIf (!config.boot.initrd.systemd.enable) ''
163 $out/bin/bcachefs version
166 boot.initrd.postDeviceCommands = lib.mkIf (!config.boot.initrd.systemd.enable) (commonFunctions + lib.concatStrings (lib.mapAttrsToList openCommand bootFs));
168 boot.initrd.systemd.services = lib.mapAttrs' (mkUnits "/sysroot") bootFs;