nixos/preload: init
[NixPkgs.git] / nixos / modules / services / hardware / fwupd.nix
blob7b6c336bd22117e6e66dd9ab05cf6b94f0a775dd
1 # fwupd daemon.
3 { config, lib, pkgs, ... }:
5 with lib;
7 let
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 {} "=";
13   };
15   customEtc = {
16     "fwupd/fwupd.conf" = {
17       source = format.generate "fwupd.conf" {
18         fwupd = cfg.daemonSettings;
19         uefi_capsule = cfg.uefiCapsuleSettings;
20       };
21       # fwupd tries to chmod the file if it doesn't have the right permissions
22       mode = "0640";
23     };
24   };
26   originalEtc =
27     let
28       mkEtcFile = n: nameValuePair n { source = "${cfg.package}/etc/${n}"; };
29     in listToAttrs (map mkEtcFile cfg.package.filesInstalledToEtc);
30   extraTrustedKeys =
31     let
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"
41       '';
42     };
43   };
44   remotes = (foldl'
45     (configFiles: remote: configFiles // (enableRemote cfg.package remote))
46     {}
47     cfg.extraRemotes
48   ) // (
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")
54   );
56 in {
58   ###### interface
59   options = {
60     services.fwupd = {
61       enable = mkOption {
62         type = types.bool;
63         default = false;
64         description = lib.mdDoc ''
65           Whether to enable fwupd, a DBus service that allows
66           applications to update firmware.
67         '';
68       };
70       extraTrustedKeys = mkOption {
71         type = types.listOf types.path;
72         default = [];
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.
76         '';
77       };
79       extraRemotes = mkOption {
80         type = with types; listOf str;
81         default = [];
82         example = [ "lvfs-testing" ];
83         description = lib.mdDoc ''
84           Enables extra remotes in fwupd. See `/etc/fwupd/remotes.d`.
85         '';
86       };
88       enableTestRemote = mkOption {
89         type = types.bool;
90         default = false;
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).
94         '';
95       };
97       package = mkOption {
98         type = types.package;
99         default = pkgs.fwupd;
100         defaultText = literalExpression "pkgs.fwupd";
101         description = lib.mdDoc ''
102           Which fwupd package to use.
103         '';
104       };
106       daemonSettings = mkOption {
107         type = types.submodule {
108           freeformType = format.type.nestedTypes.elemType;
109           options = {
110             DisabledDevices = mkOption {
111               type = types.listOf types.str;
112               default = [];
113               example = [ "2082b5e0-7a64-478a-b1b2-e3404fab6dad" ];
114               description = lib.mdDoc ''
115                 List of device GUIDs to be disabled.
116               '';
117             };
119             DisabledPlugins = mkOption {
120               type = types.listOf types.str;
121               default = [];
122               example = [ "udev" ];
123               description = lib.mdDoc ''
124                 List of plugins to be disabled.
125               '';
126             };
128             EspLocation = mkOption {
129               type = types.path;
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
135               '';
136             };
137           };
138         };
139         default = {};
140         description = lib.mdDoc ''
141           Configurations for the fwupd daemon.
142         '';
143       };
145       uefiCapsuleSettings = mkOption {
146         type = types.submodule {
147           freeformType = format.type.nestedTypes.elemType;
148         };
149         default = {};
150         description = lib.mdDoc ''
151           UEFI capsule configurations for the fwupd daemon.
152         '';
153       };
154     };
155   };
157   imports = [
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" ])
162   ];
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;
170     };
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;
184     systemd = {
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";
193       };
195       timers.fwupd-refresh.wantedBy = [ "timers.target" ];
196     };
198     users.users.fwupd-refresh = {
199       isSystemUser = true;
200       group = "fwupd-refresh";
201     };
202     users.groups.fwupd-refresh = {};
204     security.polkit.enable = true;
205   };
207   meta = {
208     maintainers = pkgs.fwupd.meta.maintainers;
209   };