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 = "644";
27 gid = config.ids.gids.fcron;
28 };
29
30in
31
32{
33
34 ###### interface
35
36 options = {
37
38 services.fcron = {
39
40 enable = mkOption {
41 type = types.bool;
42 default = false;
43 description = "Whether to enable the <command>fcron</command> daemon.";
44 };
45
46 allow = mkOption {
47 type = types.listOf types.str;
48 default = [ "all" ];
49 description = ''
50 Users allowed to use fcrontab and fcrondyn (one name per
51 line, <literal>all</literal> for everyone).
52 '';
53 };
54
55 deny = mkOption {
56 type = types.listOf types.str;
57 default = [];
58 description = "Users forbidden from using fcron.";
59 };
60
61 maxSerialJobs = mkOption {
62 type = types.int;
63 default = 1;
64 description = "Maximum number of serial jobs which can run simultaneously.";
65 };
66
67 queuelen = mkOption {
68 type = types.nullOr types.int;
69 default = null;
70 description = "Number of jobs the serial queue and the lavg queue can contain.";
71 };
72
73 systab = mkOption {
74 type = types.lines;
75 default = "";
76 description = ''The "system" crontab contents.'';
77 };
78 };
79
80 };
81
82
83 ###### implementation
84
85 config = mkIf cfg.enable {
86
87 services.fcron.systab = systemCronJobs;
88
89 environment.etc =
90 [ (allowdeny "allow" (cfg.allow))
91 (allowdeny "deny" cfg.deny)
92 # see man 5 fcron.conf
93 { source = pkgs.writeText "fcron.conf" ''
94 fcrontabs = /var/spool/fcron
95 pidfile = /var/run/fcron.pid
96 fifofile = /var/run/fcron.fifo
97 fcronallow = /etc/fcron.allow
98 fcrondeny = /etc/fcron.deny
99 shell = /bin/sh
100 sendmail = /run/wrappers/bin/sendmail
101 editor = ${pkgs.vim}/bin/vim
102 '';
103 target = "fcron.conf";
104 gid = config.ids.gids.fcron;
105 mode = "0644";
106 }
107 ];
108
109 environment.systemPackages = [ pkgs.fcron ];
110 users.extraUsers.fcron = {
111 uid = config.ids.uids.fcron;
112 home = "/var/spool/fcron";
113 group = "fcron";
114 };
115 users.groups.fcron.gid = config.ids.gids.fcron;
116
117 security.wrappers = {
118 fcrontab = {
119 source = "${pkgs.fcron}/bin/fcrontab";
120 owner = "fcron";
121 group = "fcron";
122 setgid = true;
123 };
124 fcrondyn = {
125 source = "${pkgs.fcron}/bin/fcrondyn";
126 owner = "fcron";
127 group = "fcron";
128 setgid = true;
129 };
130 fcronsighup = {
131 source = "${pkgs.fcron}/bin/fcronsighup";
132 group = "fcron";
133 };
134 };
135 systemd.services.fcron = {
136 description = "fcron daemon";
137 after = [ "local-fs.target" ];
138 wantedBy = [ "multi-user.target" ];
139
140 # FIXME use specific path
141 environment = {
142 PATH = "/run/current-system/sw/bin";
143 };
144
145 preStart = ''
146 install \
147 --mode 0770 \
148 --owner fcron \
149 --group fcron \
150 --directory /var/spool/fcron
151 # load system crontab file
152 /run/wrappers/bin/fcrontab -u systab ${pkgs.writeText "systab" cfg.systab}
153 '';
154
155 serviceConfig = {
156 Type = "forking";
157 ExecStart = "${pkgs.fcron}/sbin/fcron -m ${toString cfg.maxSerialJobs} ${queuelen}";
158 };
159 };
160 };
161}