vuls: init at 0.27.0
[NixPkgs.git] / nixos / modules / services / monitoring / smartd.nix
blob65b6259c12bd82228f718706a84786568b3cf42f
1 { config, lib, options, pkgs, ... }:
3 with lib;
5 let
7   host = config.networking.fqdnOrHostName;
9   cfg = config.services.smartd;
10   opt = options.services.smartd;
12   nm = cfg.notifications.mail;
13   ns = cfg.notifications.systembus-notify;
14   nw = cfg.notifications.wall;
15   nx = cfg.notifications.x11;
17   smartdNotify = pkgs.writeScript "smartd-notify.sh" ''
18     #! ${pkgs.runtimeShell}
19     ${optionalString nm.enable ''
20       {
21       ${pkgs.coreutils}/bin/cat << EOF
22       From: smartd on ${host} <${nm.sender}>
23       To: ${nm.recipient}
24       Subject: $SMARTD_SUBJECT
26       $SMARTD_FULLMESSAGE
27       EOF
29       ${pkgs.smartmontools}/sbin/smartctl -a -d "$SMARTD_DEVICETYPE" "$SMARTD_DEVICE"
30       } | ${nm.mailer} -i "${nm.recipient}"
31     ''}
32     ${optionalString ns.enable ''
33       ${pkgs.dbus}/bin/dbus-send --system \
34         / net.nuetzlich.SystemNotifications.Notify \
35         "string:Problem detected with disk: $SMARTD_DEVICESTRING" \
36         "string:Warning message from smartd is: $SMARTD_MESSAGE"
37     ''}
38     ${optionalString nw.enable ''
39       {
40       ${pkgs.coreutils}/bin/cat << EOF
41       Problem detected with disk: $SMARTD_DEVICESTRING
42       Warning message from smartd is:
44       $SMARTD_MESSAGE
45       EOF
46       } | ${pkgs.util-linux}/bin/wall 2>/dev/null
47     ''}
48     ${optionalString nx.enable ''
49       export DISPLAY=${nx.display}
50       {
51       ${pkgs.coreutils}/bin/cat << EOF
52       Problem detected with disk: $SMARTD_DEVICESTRING
53       Warning message from smartd is:
55       $SMARTD_FULLMESSAGE
56       EOF
57       } | ${pkgs.xorg.xmessage}/bin/xmessage -file - 2>/dev/null &
58     ''}
59   '';
61   notifyOpts = optionalString (nm.enable || nw.enable || nx.enable)
62     ("-m <nomailer> -M exec ${smartdNotify} " + optionalString cfg.notifications.test "-M test ");
64   smartdConf = pkgs.writeText "smartd.conf" ''
65     # Autogenerated smartd startup config file
66     DEFAULT ${notifyOpts}${cfg.defaults.monitored}
68     ${concatMapStringsSep "\n" (d: "${d.device} ${d.options}") cfg.devices}
70     ${optionalString cfg.autodetect
71        "DEVICESCAN ${notifyOpts}${cfg.defaults.autodetected}"}
72   '';
74   smartdDeviceOpts = { ... }: {
76     options = {
78       device = mkOption {
79         example = "/dev/sda";
80         type = types.str;
81         description = "Location of the device.";
82       };
84       options = mkOption {
85         default = "";
86         example = "-d sat";
87         type = types.separatedString " ";
88         description = "Options that determine how smartd monitors the device.";
89       };
91     };
93   };
98   ###### interface
100   options = {
102     services.smartd = {
104       enable = mkEnableOption "smartd daemon from `smartmontools` package";
106       autodetect = mkOption {
107         default = true;
108         type = types.bool;
109         description = ''
110           Whenever smartd should monitor all devices connected to the
111           machine at the time it's being started (the default).
113           Set to false to monitor the devices listed in
114           {option}`services.smartd.devices` only.
115         '';
116       };
118       extraOptions = mkOption {
119         default = [];
120         type = types.listOf types.str;
121         example = ["-A /var/log/smartd/" "--interval=3600"];
122         description = ''
123           Extra command-line options passed to the `smartd`
124           daemon on startup.
126           (See `man 8 smartd`.)
127         '';
128       };
130       notifications = {
132         mail = {
133           enable = mkOption {
134             default = config.services.mail.sendmailSetuidWrapper != null;
135             defaultText = literalExpression "config.services.mail.sendmailSetuidWrapper != null";
136             type = types.bool;
137             description = "Whenever to send e-mail notifications.";
138           };
140           sender = mkOption {
141             default = "root";
142             example = "example@domain.tld";
143             type = types.str;
144             description = ''
145               Sender of the notification messages.
146               Acts as the value of `email` in the emails' `From: ...` field.
147             '';
148           };
150           recipient = mkOption {
151             default = "root";
152             type = types.str;
153             description = "Recipient of the notification messages.";
154           };
156           mailer = mkOption {
157             default = "/run/wrappers/bin/sendmail";
158             type = types.path;
159             description = ''
160               Sendmail-compatible binary to be used to send the messages.
162               You should probably enable
163               {option}`services.postfix` or some other MTA for
164               this to work.
165             '';
166           };
167         };
169         systembus-notify = {
170           enable = mkOption {
171             default = false;
172             type = types.bool;
173             description = ''
174               Whenever to send systembus-notify notifications.
176               WARNING: enabling this option (while convenient) should *not* be done on a
177               machine where you do not trust the other users as it allows any other
178               local user to DoS your session by spamming notifications.
180               To actually see the notifications in your GUI session, you need to have
181               `systembus-notify` running as your user, which this
182               option handles by enabling {option}`services.systembus-notify`.
183             '';
184           };
185         };
187         wall = {
188           enable = mkOption {
189             default = true;
190             type = types.bool;
191             description = "Whenever to send wall notifications to all users.";
192           };
193         };
195         x11 = {
196           enable = mkOption {
197             default = config.services.xserver.enable;
198             defaultText = literalExpression "config.services.xserver.enable";
199             type = types.bool;
200             description = "Whenever to send X11 xmessage notifications.";
201           };
203           display = mkOption {
204             default = ":${toString config.services.xserver.display}";
205             defaultText = literalExpression ''":''${toString config.services.xserver.display}"'';
206             type = types.str;
207             description = "DISPLAY to send X11 notifications to.";
208           };
209         };
211         test = mkOption {
212           default = false;
213           type = types.bool;
214           description = "Whenever to send a test notification on startup.";
215         };
217       };
219       defaults = {
220         monitored = mkOption {
221           default = "-a";
222           type = types.separatedString " ";
223           example = "-a -o on -s (S/../.././02|L/../../7/04)";
224           description = ''
225             Common default options for explicitly monitored (listed in
226             {option}`services.smartd.devices`) devices.
228             The default value turns on monitoring of all the things (see
229             `man 5 smartd.conf`).
231             The example also turns on SMART Automatic Offline Testing on
232             startup, and schedules short self-tests daily, and long
233             self-tests weekly.
234           '';
235         };
237         autodetected = mkOption {
238           default = cfg.defaults.monitored;
239           defaultText = literalExpression "config.${opt.defaults.monitored}";
240           type = types.separatedString " ";
241           description = ''
242             Like {option}`services.smartd.defaults.monitored`, but for the
243             autodetected devices.
244           '';
245         };
246       };
248       devices = mkOption {
249         default = [];
250         example = [ { device = "/dev/sda"; } { device = "/dev/sdb"; options = "-d sat"; } ];
251         type = with types; listOf (submodule smartdDeviceOpts);
252         description = "List of devices to monitor.";
253       };
255     };
257   };
260   ###### implementation
262   config = mkIf cfg.enable {
264     assertions = [ {
265       assertion = cfg.autodetect || cfg.devices != [];
266       message = "smartd can't run with both disabled autodetect and an empty list of devices to monitor.";
267     } ];
269     systemd.services.smartd = {
270       description = "S.M.A.R.T. Daemon";
271       wantedBy = [ "multi-user.target" ];
272       serviceConfig = {
273         Type = "notify";
274         ExecStart = "${pkgs.smartmontools}/sbin/smartd ${lib.concatStringsSep " " cfg.extraOptions} --no-fork --configfile=${smartdConf}";
275       };
276     };
278     services.systembus-notify.enable = mkDefault ns.enable;
280   };