3 { config, lib, pkgs, ... }:
8 cfg = config.services.fwupd;
10 format = pkgs.formats.ini {
11 listToValue = l: lib.concatStringsSep ";" (map (s: generators.mkValueStringDefault {} s) l);
12 mkKeyValue = generators.mkKeyValueDefault {} "=";
16 "fwupd/fwupd.conf" = {
17 source = format.generate "fwupd.conf" {
18 fwupd = cfg.daemonSettings;
19 uefi_capsule = cfg.uefiCapsuleSettings;
21 # fwupd tries to chmod the file if it doesn't have the right permissions
28 mkEtcFile = n: nameValuePair n { source = "${cfg.package}/etc/${n}"; };
29 in listToAttrs (map mkEtcFile cfg.package.filesInstalledToEtc);
32 mkName = p: "pki/fwupd/${baseNameOf (toString p)}";
33 mkEtcFile = p: nameValuePair (mkName p) { source = p; };
34 in listToAttrs (map mkEtcFile cfg.extraTrustedKeys);
36 enableRemote = base: remote: {
37 "fwupd/remotes.d/${remote}.conf" = {
38 source = pkgs.runCommand "${remote}-enabled.conf" {} ''
39 sed "s,^Enabled=false,Enabled=true," \
40 "${base}/etc/fwupd/remotes.d/${remote}.conf" > "$out"
45 (configFiles: remote: configFiles // (enableRemote cfg.package remote))
49 # We cannot include the file in $out and rely on filesInstalledToEtc
50 # to install it because it would create a cyclic dependency between
51 # the outputs. We also need to enable the remote,
52 # which should not be done by default.
53 lib.optionalAttrs cfg.enableTestRemote (enableRemote cfg.package.installedTests "fwupd-tests")
64 description = lib.mdDoc ''
65 Whether to enable fwupd, a DBus service that allows
66 applications to update firmware.
70 extraTrustedKeys = mkOption {
71 type = types.listOf types.path;
73 example = literalExpression "[ /etc/nixos/fwupd/myfirmware.pem ]";
74 description = lib.mdDoc ''
75 Installing a public key allows firmware signed with a matching private key to be recognized as trusted, which may require less authentication to install than for untrusted files. By default trusted firmware can be upgraded (but not downgraded) without the user or administrator password. Only very few keys are installed by default.
79 extraRemotes = mkOption {
80 type = with types; listOf str;
82 example = [ "lvfs-testing" ];
83 description = lib.mdDoc ''
84 Enables extra remotes in fwupd. See `/etc/fwupd/remotes.d`.
88 enableTestRemote = mkOption {
91 description = lib.mdDoc ''
92 Whether to enable test remote. This is used by
93 [installed tests](https://github.com/fwupd/fwupd/blob/master/data/installed-tests/README.md).
100 defaultText = literalExpression "pkgs.fwupd";
101 description = lib.mdDoc ''
102 Which fwupd package to use.
106 daemonSettings = mkOption {
107 type = types.submodule {
108 freeformType = format.type.nestedTypes.elemType;
110 DisabledDevices = mkOption {
111 type = types.listOf types.str;
113 example = [ "2082b5e0-7a64-478a-b1b2-e3404fab6dad" ];
114 description = lib.mdDoc ''
115 List of device GUIDs to be disabled.
119 DisabledPlugins = mkOption {
120 type = types.listOf types.str;
122 example = [ "udev" ];
123 description = lib.mdDoc ''
124 List of plugins to be disabled.
128 EspLocation = mkOption {
130 default = config.boot.loader.efi.efiSysMountPoint;
131 defaultText = lib.literalExpression "config.boot.loader.efi.efiSysMountPoint";
132 description = lib.mdDoc ''
133 The EFI system partition (ESP) path used if UDisks is not available
134 or if this partition is not mounted at /boot/efi, /boot, or /efi
140 description = lib.mdDoc ''
141 Configurations for the fwupd daemon.
145 uefiCapsuleSettings = mkOption {
146 type = types.submodule {
147 freeformType = format.type.nestedTypes.elemType;
150 description = lib.mdDoc ''
151 UEFI capsule configurations for the fwupd daemon.
158 (mkRenamedOptionModule [ "services" "fwupd" "blacklistDevices"] [ "services" "fwupd" "daemonSettings" "DisabledDevices" ])
159 (mkRenamedOptionModule [ "services" "fwupd" "blacklistPlugins"] [ "services" "fwupd" "daemonSettings" "DisabledPlugins" ])
160 (mkRenamedOptionModule [ "services" "fwupd" "disabledDevices" ] [ "services" "fwupd" "daemonSettings" "DisabledDevices" ])
161 (mkRenamedOptionModule [ "services" "fwupd" "disabledPlugins" ] [ "services" "fwupd" "daemonSettings" "DisabledPlugins" ])
164 ###### implementation
165 config = mkIf cfg.enable {
166 # Disable test related plug-ins implicitly so that users do not have to care about them.
167 services.fwupd.daemonSettings = {
168 DisabledPlugins = cfg.package.defaultDisabledPlugins;
169 EspLocation = config.boot.loader.efi.efiSysMountPoint;
172 environment.systemPackages = [ cfg.package ];
174 # customEtc overrides some files from the package
175 environment.etc = originalEtc // customEtc // extraTrustedKeys // remotes;
177 services.dbus.packages = [ cfg.package ];
179 services.udev.packages = [ cfg.package ];
181 # required to update the firmware of disks
182 services.udisks2.enable = true;
185 packages = [ cfg.package ];
187 # fwupd-refresh expects a user that we do not create, so just run with DynamicUser
188 # instead and ensure we take ownership of /var/lib/fwupd
189 services.fwupd-refresh.serviceConfig = {
190 StateDirectory = "fwupd";
191 # Better for debugging, upstream sets stderr to null for some reason..
192 StandardError = "inherit";
195 timers.fwupd-refresh.wantedBy = [ "timers.target" ];
198 users.users.fwupd-refresh = {
200 group = "fwupd-refresh";
202 users.groups.fwupd-refresh = {};
204 security.polkit.enable = true;
208 maintainers = pkgs.fwupd.meta.maintainers;