at master 15 kB view raw
1{ 2 config, 3 lib, 4 options, 5 pkgs, 6 ... 7}: 8 9with lib; 10 11let 12 13 plymouth = pkgs.plymouth.override { 14 systemd = config.boot.initrd.systemd.package; 15 }; 16 17 cfg = config.boot.plymouth; 18 opt = options.boot.plymouth; 19 20 nixosBreezePlymouth = pkgs.kdePackages.breeze-plymouth.override { 21 logoFile = cfg.logo; 22 logoName = "nixos"; 23 osName = config.system.nixos.distroName; 24 osVersion = config.system.nixos.release; 25 }; 26 27 plymouthLogos = pkgs.runCommand "plymouth-logos" { inherit (cfg) logo; } '' 28 mkdir -p $out 29 30 # For themes that are compiled with PLYMOUTH_LOGO_FILE 31 mkdir -p $out/etc/plymouth 32 ln -s $logo $out/etc/plymouth/logo.png 33 34 # Logo for bgrt theme 35 # Note this is technically an abuse of watermark for the bgrt theme 36 # See: https://gitlab.freedesktop.org/plymouth/plymouth/-/issues/95#note_813768 37 mkdir -p $out/share/plymouth/themes/spinner 38 ln -s $logo $out/share/plymouth/themes/spinner/watermark.png 39 40 # Logo for spinfinity theme 41 # See: https://gitlab.freedesktop.org/plymouth/plymouth/-/issues/106 42 mkdir -p $out/share/plymouth/themes/spinfinity 43 ln -s $logo $out/share/plymouth/themes/spinfinity/header-image.png 44 45 # Logo for catppuccin (two-step) theme 46 for flavour in mocha macchiato latte frappe 47 do 48 mkdir -p $out/share/plymouth/themes/catppuccin-"$flavour" 49 ln -s $logo $out/share/plymouth/themes/catppuccin-"$flavour"/header-image.png 50 done 51 ''; 52 53 themesEnv = pkgs.buildEnv { 54 name = "plymouth-themes"; 55 paths = [ 56 plymouth 57 plymouthLogos 58 ] 59 ++ cfg.themePackages; 60 }; 61 62 configFile = pkgs.writeText "plymouthd.conf" '' 63 [Daemon] 64 ShowDelay=0 65 DeviceTimeout=8 66 Theme=${cfg.theme} 67 ${cfg.extraConfig} 68 ''; 69 70 checkIfThemeExists = '' 71 # Check if the actual requested theme is here 72 if [[ ! -d ${themesEnv}/share/plymouth/themes/${cfg.theme} ]]; then 73 echo "The requested theme: ${cfg.theme} is not provided by any of the packages in boot.plymouth.themePackages" 74 echo "The following themes exist: $(ls ${themesEnv}/share/plymouth/themes/)" 75 exit 1 76 fi 77 ''; 78 79 # 'emergency.serivce' and 'rescue.service' have 80 # 'ExecStartPre=-plymouth quit --wait', but 'plymouth' is not on 81 # their 'ExecSearchPath'. We could set 'ExecSearchPath', but it 82 # overrides 'DefaultEnvironment=PATH=...', which is trouble for the 83 # initrd shell. It's simpler to just reset 'ExecStartPre' with an 84 # empty string and then set it to exactly what we want. 85 preStartQuitFixup = { 86 serviceConfig.ExecStartPre = [ 87 "" 88 "${plymouth}/bin/plymouth quit --wait" 89 ]; 90 }; 91 92in 93 94{ 95 96 options = { 97 98 boot.plymouth = { 99 100 enable = mkEnableOption "Plymouth boot splash screen"; 101 102 font = mkOption { 103 default = "${pkgs.dejavu_fonts.minimal}/share/fonts/truetype/DejaVuSans.ttf"; 104 defaultText = literalExpression ''"''${pkgs.dejavu_fonts.minimal}/share/fonts/truetype/DejaVuSans.ttf"''; 105 type = types.path; 106 description = '' 107 Font file made available for displaying text on the splash screen. 108 ''; 109 }; 110 111 themePackages = mkOption { 112 default = lib.optional (cfg.theme == "breeze") nixosBreezePlymouth; 113 defaultText = literalMD '' 114 A NixOS branded variant of the breeze theme when 115 `config.${opt.theme} == "breeze"`, otherwise 116 `[ ]`. 117 ''; 118 type = types.listOf types.package; 119 description = '' 120 Extra theme packages for plymouth. 121 ''; 122 }; 123 124 theme = mkOption { 125 default = "bgrt"; 126 type = types.str; 127 description = '' 128 Splash screen theme. 129 ''; 130 }; 131 132 logo = mkOption { 133 type = types.path; 134 # Dimensions are 48x48 to match GDM logo 135 default = "${pkgs.nixos-icons}/share/icons/hicolor/48x48/apps/nix-snowflake-white.png"; 136 defaultText = literalExpression ''"''${pkgs.nixos-icons}/share/icons/hicolor/48x48/apps/nix-snowflake-white.png"''; 137 example = literalExpression '' 138 pkgs.fetchurl { 139 url = "https://nixos.org/logo/nixos-hires.png"; 140 sha256 = "1ivzgd7iz0i06y36p8m5w48fd8pjqwxhdaavc0pxs7w1g7mcy5si"; 141 } 142 ''; 143 description = '' 144 Logo which is displayed on the splash screen. 145 Currently supports PNG file format only. 146 ''; 147 }; 148 149 extraConfig = mkOption { 150 type = types.lines; 151 default = ""; 152 description = '' 153 Literal string to append to `configFile` 154 and the config file generated by the plymouth module. 155 ''; 156 }; 157 158 }; 159 160 }; 161 162 config = mkIf cfg.enable { 163 164 boot.kernelParams = [ "splash" ]; 165 166 # To be discoverable by systemd. 167 environment.systemPackages = [ plymouth ]; 168 169 environment.etc."plymouth/plymouthd.conf".source = configFile; 170 environment.etc."plymouth/plymouthd.defaults".source = 171 "${plymouth}/share/plymouth/plymouthd.defaults"; 172 environment.etc."plymouth/logo.png".source = cfg.logo; 173 environment.etc."plymouth/themes".source = "${themesEnv}/share/plymouth/themes"; 174 # XXX: Needed because we supply a different set of plugins in initrd. 175 environment.etc."plymouth/plugins".source = "${plymouth}/lib/plymouth"; 176 177 systemd.tmpfiles.rules = [ 178 "d /run/plymouth 0755 root root 0 -" 179 "L+ /run/plymouth/plymouthd.defaults - - - - /etc/plymouth/plymouthd.defaults" 180 "L+ /run/plymouth/themes - - - - /etc/plymouth/themes" 181 "L+ /run/plymouth/plugins - - - - /etc/plymouth/plugins" 182 ]; 183 184 systemd.packages = [ plymouth ]; 185 186 systemd.services.plymouth-kexec.wantedBy = [ "kexec.target" ]; 187 systemd.services.plymouth-halt.wantedBy = [ "halt.target" ]; 188 systemd.services.plymouth-quit-wait.wantedBy = [ "multi-user.target" ]; 189 systemd.services.plymouth-quit.wantedBy = [ "multi-user.target" ]; 190 systemd.services.plymouth-poweroff.wantedBy = [ "poweroff.target" ]; 191 systemd.services.plymouth-reboot.wantedBy = [ "reboot.target" ]; 192 systemd.services.plymouth-read-write.wantedBy = [ "sysinit.target" ]; 193 systemd.services.systemd-ask-password-plymouth.wantedBy = [ "sysinit.target" ]; 194 systemd.paths.systemd-ask-password-plymouth.wantedBy = [ "sysinit.target" ]; 195 196 # Prevent Plymouth taking over the screen during system updates. 197 systemd.services.plymouth-start.restartIfChanged = false; 198 199 systemd.services.rescue = preStartQuitFixup; 200 systemd.services.emergency = preStartQuitFixup; 201 202 boot.initrd.systemd = { 203 extraBin.plymouth = "${plymouth}/bin/plymouth"; # for the recovery shell 204 storePaths = [ 205 "${lib.getBin config.boot.initrd.systemd.package}/bin/systemd-tty-ask-password-agent" 206 "${plymouth}/bin/plymouthd" 207 "${plymouth}/sbin/plymouthd" 208 ]; 209 packages = [ plymouth ]; # systemd units 210 211 services.rescue = preStartQuitFixup; 212 services.emergency = preStartQuitFixup; 213 214 contents = { 215 # Files 216 "/etc/plymouth/plymouthd.conf".source = configFile; 217 "/etc/plymouth/logo.png".source = cfg.logo; 218 "/etc/plymouth/plymouthd.defaults".source = "${plymouth}/share/plymouth/plymouthd.defaults"; 219 # Directories 220 "/etc/plymouth/plugins".source = pkgs.runCommand "plymouth-initrd-plugins" { } ( 221 checkIfThemeExists 222 + '' 223 moduleName="$(sed -n 's,ModuleName *= *,,p' ${themesEnv}/share/plymouth/themes/${cfg.theme}/${cfg.theme}.plymouth)" 224 225 mkdir -p $out/renderers 226 # module might come from a theme 227 cp ${themesEnv}/lib/plymouth/*.so $out 228 cp ${plymouth}/lib/plymouth/renderers/*.so $out/renderers 229 # useless in the initrd, and adds several megabytes to the closure 230 rm $out/renderers/x11.so 231 '' 232 ); 233 "/etc/plymouth/themes".source = pkgs.runCommand "plymouth-initrd-themes" { } ( 234 checkIfThemeExists 235 + '' 236 mkdir -p $out/${cfg.theme} 237 cp -r ${themesEnv}/share/plymouth/themes/${cfg.theme}/* $out/${cfg.theme} 238 # Copy more themes if the theme depends on others 239 for theme in $(grep -hRo '/share/plymouth/themes/.*$' $out | xargs -n1 basename); do 240 if [[ -d "${themesEnv}/share/plymouth/themes/$theme" ]]; then 241 if [[ ! -d "$out/$theme" ]]; then 242 echo "Adding dependent theme: $theme" 243 mkdir -p "$out/$theme" 244 cp -r "${themesEnv}/share/plymouth/themes/$theme"/* "$out/$theme" 245 fi 246 else 247 echo "Missing theme dependency: $theme" 248 fi 249 done 250 # Fixup references 251 for theme in $out/*/*.plymouth; do 252 sed -i "s,${builtins.storeDir}/.*/share/plymouth/themes,$out," "$theme" 253 done 254 '' 255 ); 256 257 # Fonts 258 "/etc/plymouth/fonts".source = pkgs.runCommand "plymouth-initrd-fonts" { } '' 259 mkdir -p $out 260 cp ${escapeShellArg cfg.font} $out 261 ''; 262 "/etc/fonts/fonts.conf".text = '' 263 <?xml version="1.0"?> 264 <!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd"> 265 <fontconfig> 266 <dir>/etc/plymouth/fonts</dir> 267 </fontconfig> 268 ''; 269 }; 270 # Properly enable units. These are the units that arch copies 271 services = { 272 plymouth-halt.wantedBy = [ "halt.target" ]; 273 plymouth-kexec.wantedBy = [ "kexec.target" ]; 274 plymouth-poweroff.wantedBy = [ "poweroff.target" ]; 275 plymouth-quit-wait.wantedBy = [ "multi-user.target" ]; 276 plymouth-quit.wantedBy = [ "multi-user.target" ]; 277 plymouth-read-write.wantedBy = [ "sysinit.target" ]; 278 plymouth-reboot.wantedBy = [ "reboot.target" ]; 279 plymouth-start.wantedBy = [ 280 "initrd-switch-root.target" 281 "sysinit.target" 282 ]; 283 plymouth-switch-root-initramfs.wantedBy = [ 284 "halt.target" 285 "kexec.target" 286 "plymouth-switch-root-initramfs.service" 287 "poweroff.target" 288 "reboot.target" 289 ]; 290 plymouth-switch-root.wantedBy = [ "initrd-switch-root.target" ]; 291 }; 292 # Link in runtime files before starting 293 services.plymouth-start.preStart = '' 294 mkdir -p /run/plymouth 295 ln -sf /etc/plymouth/{plymouthd.defaults,themes,plugins} /run/plymouth/ 296 ''; 297 }; 298 299 # Insert required udev rules. We take stage 2 systemd because the udev 300 # rules are only generated when building with logind. 301 boot.initrd.services.udev.packages = [ 302 (pkgs.runCommand "initrd-plymouth-udev-rules" { } '' 303 mkdir -p $out/etc/udev/rules.d 304 cp ${config.systemd.package.out}/lib/udev/rules.d/{70-uaccess,71-seat}.rules $out/etc/udev/rules.d 305 sed -i '/loginctl/d' $out/etc/udev/rules.d/71-seat.rules 306 '') 307 ]; 308 309 boot.initrd.extraUtilsCommands = lib.mkIf (!config.boot.initrd.systemd.enable) ( 310 '' 311 copy_bin_and_libs ${plymouth}/bin/plymouth 312 copy_bin_and_libs ${plymouth}/bin/plymouthd 313 314 '' 315 + checkIfThemeExists 316 + '' 317 318 moduleName="$(sed -n 's,ModuleName *= *,,p' ${themesEnv}/share/plymouth/themes/${cfg.theme}/${cfg.theme}.plymouth)" 319 320 mkdir -p $out/lib/plymouth/renderers 321 # module might come from a theme 322 cp ${themesEnv}/lib/plymouth/*.so $out/lib/plymouth 323 cp ${plymouth}/lib/plymouth/renderers/*.so $out/lib/plymouth/renderers 324 # useless in the initrd, and adds several megabytes to the closure 325 rm $out/lib/plymouth/renderers/x11.so 326 327 mkdir -p $out/share/plymouth/themes 328 cp ${plymouth}/share/plymouth/plymouthd.defaults $out/share/plymouth 329 330 # Copy themes into working directory for patching 331 mkdir themes 332 333 # Use -L to copy the directories proper, not the symlinks to them. 334 # Copy all themes because they're not large assets, and bgrt depends on the ImageDir of 335 # the spinner theme. 336 cp -r -L ${themesEnv}/share/plymouth/themes/* themes 337 338 # Patch out any attempted references to the theme or plymouth's themes directory 339 chmod -R +w themes 340 find themes -type f | while read file 341 do 342 sed -i "s,${builtins.storeDir}/.*/share/plymouth/themes,$out/share/plymouth/themes,g" $file 343 done 344 345 # Install themes 346 cp -r themes/* $out/share/plymouth/themes 347 348 # Install logo 349 mkdir -p $out/etc/plymouth 350 cp -r -L ${themesEnv}/etc/plymouth $out/etc 351 352 # Setup font 353 mkdir -p $out/share/fonts 354 cp ${cfg.font} $out/share/fonts 355 mkdir -p $out/etc/fonts 356 cat > $out/etc/fonts/fonts.conf <<EOF 357 <?xml version="1.0"?> 358 <!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd"> 359 <fontconfig> 360 <dir>$out/share/fonts</dir> 361 </fontconfig> 362 EOF 363 '' 364 ); 365 366 boot.initrd.extraUtilsCommandsTest = mkIf (!config.boot.initrd.systemd.enable) '' 367 $out/bin/plymouthd --help >/dev/null 368 $out/bin/plymouth --help >/dev/null 369 ''; 370 371 boot.initrd.extraUdevRulesCommands = mkIf (!config.boot.initrd.systemd.enable) '' 372 cp ${config.systemd.package}/lib/udev/rules.d/{70-uaccess,71-seat}.rules $out 373 sed -i '/loginctl/d' $out/71-seat.rules 374 ''; 375 376 # We use `mkAfter` to ensure that LUKS password prompt would be shown earlier than the splash screen. 377 boot.initrd.preLVMCommands = mkIf (!config.boot.initrd.systemd.enable) (mkAfter '' 378 plymouth_enabled=1 379 for o in $(cat /proc/cmdline); do 380 case $o in 381 plymouth.enable=0) 382 plymouth_enabled=0 383 ;; 384 esac 385 done 386 387 if [ "$plymouth_enabled" != 0 ]; then 388 mkdir -p /etc/plymouth 389 mkdir -p /run/plymouth 390 ln -s $extraUtils/etc/plymouth/logo.png /etc/plymouth/logo.png 391 ln -s ${configFile} /etc/plymouth/plymouthd.conf 392 ln -s $extraUtils/share/plymouth/plymouthd.defaults /run/plymouth/plymouthd.defaults 393 ln -s $extraUtils/share/plymouth/themes /run/plymouth/themes 394 ln -s $extraUtils/lib/plymouth /run/plymouth/plugins 395 ln -s $extraUtils/etc/fonts /etc/fonts 396 397 plymouthd --mode=boot --pid-file=/run/plymouth/pid --attach-to-session 398 plymouth show-splash 399 fi 400 ''); 401 402 boot.initrd.postMountCommands = mkIf (!config.boot.initrd.systemd.enable) '' 403 if [ "$plymouth_enabled" != 0 ]; then 404 plymouth update-root-fs --new-root-dir="$targetRoot" 405 fi 406 ''; 407 408 # `mkBefore` to ensure that any custom prompts would be visible. 409 boot.initrd.preFailCommands = mkIf (!config.boot.initrd.systemd.enable) (mkBefore '' 410 if [ "$plymouth_enabled" != 0 ]; then 411 plymouth quit --wait 412 fi 413 ''); 414 415 }; 416 417}