1 { config, lib, options, pkgs, ... }:
4 host = config.networking.fqdnOrHostName;
6 cfg = config.services.smartd;
7 opt = options.services.smartd;
9 nm = cfg.notifications.mail;
10 ns = cfg.notifications.systembus-notify;
11 nw = cfg.notifications.wall;
12 nx = cfg.notifications.x11;
14 smartdNotify = pkgs.writeScript "smartd-notify.sh" ''
15 #! ${pkgs.runtimeShell}
16 ${lib.optionalString nm.enable ''
18 ${pkgs.coreutils}/bin/cat << EOF
19 From: smartd on ${host} <${nm.sender}>
21 Subject: $SMARTD_SUBJECT
26 ${pkgs.smartmontools}/sbin/smartctl -a -d "$SMARTD_DEVICETYPE" "$SMARTD_DEVICE"
27 } | ${nm.mailer} -i "${nm.recipient}"
29 ${lib.optionalString ns.enable ''
30 ${pkgs.dbus}/bin/dbus-send --system \
31 / net.nuetzlich.SystemNotifications.Notify \
32 "string:Problem detected with disk: $SMARTD_DEVICESTRING" \
33 "string:Warning message from smartd is: $SMARTD_MESSAGE"
35 ${lib.optionalString nw.enable ''
37 ${pkgs.coreutils}/bin/cat << EOF
38 Problem detected with disk: $SMARTD_DEVICESTRING
39 Warning message from smartd is:
43 } | ${pkgs.util-linux}/bin/wall 2>/dev/null
45 ${lib.optionalString nx.enable ''
46 export DISPLAY=${nx.display}
48 ${pkgs.coreutils}/bin/cat << EOF
49 Problem detected with disk: $SMARTD_DEVICESTRING
50 Warning message from smartd is:
54 } | ${pkgs.xorg.xmessage}/bin/xmessage -file - 2>/dev/null &
58 notifyOpts = lib.optionalString (nm.enable || nw.enable || nx.enable)
59 ("-m <nomailer> -M exec ${smartdNotify} " + lib.optionalString cfg.notifications.test "-M test ");
61 smartdConf = pkgs.writeText "smartd.conf" ''
62 # Autogenerated smartd startup config file
63 DEFAULT ${notifyOpts}${cfg.defaults.monitored}
65 ${lib.concatMapStringsSep "\n" (d: "${d.device} ${d.options}") cfg.devices}
67 ${lib.optionalString cfg.autodetect
68 "DEVICESCAN ${notifyOpts}${cfg.defaults.autodetected}"}
71 smartdDeviceOpts = { ... }: {
75 device = lib.mkOption {
78 description = "Location of the device.";
81 options = lib.mkOption {
84 type = lib.types.separatedString " ";
85 description = "Options that determine how smartd monitors the device.";
101 enable = lib.mkEnableOption "smartd daemon from `smartmontools` package";
103 autodetect = lib.mkOption {
105 type = lib.types.bool;
107 Whenever smartd should monitor all devices connected to the
108 machine at the time it's being started (the default).
110 Set to false to monitor the devices listed in
111 {option}`services.smartd.devices` only.
115 extraOptions = lib.mkOption {
117 type = lib.types.listOf lib.types.str;
118 example = ["-A /var/log/smartd/" "--interval=3600"];
120 Extra command-line options passed to the `smartd`
123 (See `man 8 smartd`.)
130 enable = lib.mkOption {
131 default = config.services.mail.sendmailSetuidWrapper != null;
132 defaultText = lib.literalExpression "config.services.mail.sendmailSetuidWrapper != null";
133 type = lib.types.bool;
134 description = "Whenever to send e-mail notifications.";
137 sender = lib.mkOption {
139 example = "example@domain.tld";
140 type = lib.types.str;
142 Sender of the notification messages.
143 Acts as the value of `email` in the emails' `From: ...` field.
147 recipient = lib.mkOption {
149 type = lib.types.str;
150 description = "Recipient of the notification messages.";
153 mailer = lib.mkOption {
154 default = "/run/wrappers/bin/sendmail";
155 type = lib.types.path;
157 Sendmail-compatible binary to be used to send the messages.
159 You should probably enable
160 {option}`services.postfix` or some other MTA for
167 enable = lib.mkOption {
169 type = lib.types.bool;
171 Whenever to send systembus-notify notifications.
173 WARNING: enabling this option (while convenient) should *not* be done on a
174 machine where you do not trust the other users as it allows any other
175 local user to DoS your session by spamming notifications.
177 To actually see the notifications in your GUI session, you need to have
178 `systembus-notify` running as your user, which this
179 option handles by enabling {option}`services.systembus-notify`.
185 enable = lib.mkOption {
187 type = lib.types.bool;
188 description = "Whenever to send wall notifications to all users.";
193 enable = lib.mkOption {
194 default = config.services.xserver.enable;
195 defaultText = lib.literalExpression "config.services.xserver.enable";
196 type = lib.types.bool;
197 description = "Whenever to send X11 xmessage notifications.";
200 display = lib.mkOption {
201 default = ":${toString config.services.xserver.display}";
202 defaultText = lib.literalExpression ''":''${toString config.services.xserver.display}"'';
203 type = lib.types.str;
204 description = "DISPLAY to send X11 notifications to.";
208 test = lib.mkOption {
210 type = lib.types.bool;
211 description = "Whenever to send a test notification on startup.";
217 monitored = lib.mkOption {
219 type = lib.types.separatedString " ";
220 example = "-a -o on -s (S/../.././02|L/../../7/04)";
222 Common default options for explicitly monitored (listed in
223 {option}`services.smartd.devices`) devices.
225 The default value turns on monitoring of all the things (see
226 `man 5 smartd.conf`).
228 The example also turns on SMART Automatic Offline Testing on
229 startup, and schedules short self-tests daily, and long
234 autodetected = lib.mkOption {
235 default = cfg.defaults.monitored;
236 defaultText = lib.literalExpression "config.${opt.defaults.monitored}";
237 type = lib.types.separatedString " ";
239 Like {option}`services.smartd.defaults.monitored`, but for the
240 autodetected devices.
245 devices = lib.mkOption {
247 example = [ { device = "/dev/sda"; } { device = "/dev/sdb"; options = "-d sat"; } ];
248 type = with lib.types; listOf (submodule smartdDeviceOpts);
249 description = "List of devices to monitor.";
257 ###### implementation
259 config = lib.mkIf cfg.enable {
262 assertion = cfg.autodetect || cfg.devices != [];
263 message = "smartd can't run with both disabled autodetect and an empty list of devices to monitor.";
266 systemd.services.smartd = {
267 description = "S.M.A.R.T. Daemon";
268 wantedBy = [ "multi-user.target" ];
271 ExecStart = "${pkgs.smartmontools}/sbin/smartd ${lib.concatStringsSep " " cfg.extraOptions} --no-fork --configfile=${smartdConf}";
275 services.systembus-notify.enable = lib.mkDefault ns.enable;