1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 cfg = config.services.fcron;
8
9 queuelen = if cfg.queuelen == null then "" else "-q ${toString cfg.queuelen}";
10
11 # Duplicate code, also found in cron.nix. Needs deduplication.
12 systemCronJobs =
13 ''
14 SHELL=${pkgs.bash}/bin/bash
15 PATH=${config.system.path}/bin:${config.system.path}/sbin
16 ${optionalString (config.services.cron.mailto != null) ''
17 MAILTO="${config.services.cron.mailto}"
18 ''}
19 NIX_CONF_DIR=/etc/nix
20 ${lib.concatStrings (map (job: job + "\n") config.services.cron.systemCronJobs)}
21 '';
22
23 allowdeny = target: users:
24 { source = pkgs.writeText "fcron.${target}" (concatStringsSep "\n" users);
25 target = "fcron.${target}";
26 mode = "600"; # fcron has some security issues.. So I guess this is most safe
27 };
28
29in
30
31{
32
33 ###### interface
34
35 options = {
36
37 services.fcron = {
38
39 enable = mkOption {
40 type = types.bool;
41 default = false;
42 description = "Whether to enable the <command>fcron</command> daemon.";
43 };
44
45 allow = mkOption {
46 type = types.listOf types.str;
47 default = [ "all" ];
48 description = ''
49 Users allowed to use fcrontab and fcrondyn (one name per
50 line, <literal>all</literal> for everyone).
51 '';
52 };
53
54 deny = mkOption {
55 type = types.listOf types.str;
56 default = [];
57 description = "Users forbidden from using fcron.";
58 };
59
60 maxSerialJobs = mkOption {
61 type = types.int;
62 default = 1;
63 description = "Maximum number of serial jobs which can run simultaneously.";
64 };
65
66 queuelen = mkOption {
67 type = types.nullOr types.int;
68 default = null;
69 description = "Number of jobs the serial queue and the lavg queue can contain.";
70 };
71
72 systab = mkOption {
73 type = types.lines;
74 default = "";
75 description = ''The "system" crontab contents.'';
76 };
77 };
78
79 };
80
81
82 ###### implementation
83
84 config = mkIf cfg.enable {
85
86 services.fcron.systab = systemCronJobs;
87
88 environment.etc =
89 [ (allowdeny "allow" (cfg.allow))
90 (allowdeny "deny" cfg.deny)
91 # see man 5 fcron.conf
92 { source = pkgs.writeText "fcon.conf" ''
93 fcrontabs = /var/spool/fcron
94 pidfile = /var/run/fcron.pid
95 fifofile = /var/run/fcron.fifo
96 fcronallow = /etc/fcron.allow
97 fcrondeny = /etc/fcron.deny
98 shell = /bin/sh
99 sendmail = /var/setuid-wrappers/sendmail
100 editor = /run/current-system/sw/bin/vi
101 '';
102 target = "fcron.conf";
103 mode = "0600"; # max allowed is 644
104 }
105 ];
106
107 environment.systemPackages = [ pkgs.fcron ];
108
109 security.setuidPrograms = [ "fcrontab" ];
110
111 systemd.services.fcron = {
112 description = "fcron daemon";
113 after = [ "local-fs.target" ];
114 wantedBy = [ "multi-user.target" ];
115
116 # FIXME use specific path
117 environment = {
118 PATH = "/run/current-system/sw/bin";
119 };
120
121 preStart = ''
122 ${pkgs.coreutils}/bin/mkdir -m 0700 -p /var/spool/fcron
123 # load system crontab file
124 ${pkgs.fcron}/bin/fcrontab -u systab ${pkgs.writeText "systab" cfg.systab}
125 '';
126
127 serviceConfig.Type = "forking";
128
129 script = "${pkgs.fcron}/sbin/fcron -m ${toString cfg.maxSerialJobs} ${queuelen}";
130 };
131 };
132}