1 { config, lib, options, pkgs, ... }:
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 ''
21 ${pkgs.coreutils}/bin/cat << EOF
22 From: smartd on ${host} <${nm.sender}>
24 Subject: $SMARTD_SUBJECT
29 ${pkgs.smartmontools}/sbin/smartctl -a -d "$SMARTD_DEVICETYPE" "$SMARTD_DEVICE"
30 } | ${nm.mailer} -i "${nm.recipient}"
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"
38 ${optionalString nw.enable ''
40 ${pkgs.coreutils}/bin/cat << EOF
41 Problem detected with disk: $SMARTD_DEVICESTRING
42 Warning message from smartd is:
46 } | ${pkgs.util-linux}/bin/wall 2>/dev/null
48 ${optionalString nx.enable ''
49 export DISPLAY=${nx.display}
51 ${pkgs.coreutils}/bin/cat << EOF
52 Problem detected with disk: $SMARTD_DEVICESTRING
53 Warning message from smartd is:
57 } | ${pkgs.xorg.xmessage}/bin/xmessage -file - 2>/dev/null &
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}"}
74 smartdDeviceOpts = { ... }: {
81 description = "Location of the device.";
87 type = types.separatedString " ";
88 description = "Options that determine how smartd monitors the device.";
104 enable = mkEnableOption "smartd daemon from `smartmontools` package";
106 autodetect = mkOption {
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.
118 extraOptions = mkOption {
120 type = types.listOf types.str;
121 example = ["-A /var/log/smartd/" "--interval=3600"];
123 Extra command-line options passed to the `smartd`
126 (See `man 8 smartd`.)
134 default = config.services.mail.sendmailSetuidWrapper != null;
135 defaultText = literalExpression "config.services.mail.sendmailSetuidWrapper != null";
137 description = "Whenever to send e-mail notifications.";
142 example = "example@domain.tld";
145 Sender of the notification messages.
146 Acts as the value of `email` in the emails' `From: ...` field.
150 recipient = mkOption {
153 description = "Recipient of the notification messages.";
157 default = "/run/wrappers/bin/sendmail";
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
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`.
191 description = "Whenever to send wall notifications to all users.";
197 default = config.services.xserver.enable;
198 defaultText = literalExpression "config.services.xserver.enable";
200 description = "Whenever to send X11 xmessage notifications.";
204 default = ":${toString config.services.xserver.display}";
205 defaultText = literalExpression ''":''${toString config.services.xserver.display}"'';
207 description = "DISPLAY to send X11 notifications to.";
214 description = "Whenever to send a test notification on startup.";
220 monitored = mkOption {
222 type = types.separatedString " ";
223 example = "-a -o on -s (S/../.././02|L/../../7/04)";
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
237 autodetected = mkOption {
238 default = cfg.defaults.monitored;
239 defaultText = literalExpression "config.${opt.defaults.monitored}";
240 type = types.separatedString " ";
242 Like {option}`services.smartd.defaults.monitored`, but for the
243 autodetected devices.
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.";
260 ###### implementation
262 config = mkIf cfg.enable {
265 assertion = cfg.autodetect || cfg.devices != [];
266 message = "smartd can't run with both disabled autodetect and an empty list of devices to monitor.";
269 systemd.services.smartd = {
270 description = "S.M.A.R.T. Daemon";
271 wantedBy = [ "multi-user.target" ];
274 ExecStart = "${pkgs.smartmontools}/sbin/smartd ${lib.concatStringsSep " " cfg.extraOptions} --no-fork --configfile=${smartdConf}";
278 services.systembus-notify.enable = mkDefault ns.enable;