summary refs log tree commit diff
path: root/modules/services/scheduling/fcron.nix
blob: 95ff918eb6d797e9aff7d1e2ce2a7f4a46567cb3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
{ config, pkgs, ... }:

with pkgs.lib;

let

  cfg = config.services.fcron;

  queuelen = if cfg.queuelen == "" then "" else "-q ${toString cfg.queuelen}";

  systemCronJobs =
    ''
      SHELL=${pkgs.bash}/bin/bash
      PATH=${config.system.path}/bin:${config.system.path}/sbin
      MAILTO="${config.services.cron.mailto}"
      NIX_CONF_DIR=/etc/nix
      ${pkgs.lib.concatStrings (map (job: job + "\n") config.services.cron.systemCronJobs)}
    '';

  allowdeny = target: users:
    { source = pkgs.writeText "fcron.${target}" (concatStringsSep "\n" users);
      target = "fcron.${target}";
      mode = "600"; # fcron has some security issues.. So I guess this is most safe
    };

in

{

  ###### interface

  options = {

    services.fcron = {

      enable = mkOption {
        default = false;
        description = "Whether to enable the `fcron' daemon.";
      };

      allow = mkOption {
        default = [ "all" ];
        description = ''
          Users allowed to use fcrontab and fcrondyn (one name per line, "all" for everyone).
        '';
      };

      deny = mkOption {
        default = [];
        description = "Users forbidden from using fcron.";
      };

      maxSerialJobs = mkOption {
        default = 1;
        description = "Maximum number of serial jobs which can run simultaneously.";
      };

      queuelen = mkOption {
        default = "";
        description = "Number of jobs the serial queue and the lavg queue can contain - empty to net set this number (-q)";
      };

      systab = mkOption {
        default = "";
        description = ''The "system" crontab contents.'';
      };
    };

  };


  ###### implementation

  config = mkIf cfg.enable {

    services.fcron.systab = systemCronJobs;

    environment.etc =
      [ (allowdeny "allow" (cfg.allow))
        (allowdeny "deny" cfg.deny)
        # see man 5 fcron.conf
        { source = pkgs.writeText "fcon.conf" ''
            fcrontabs   =       /var/spool/fcron
            pidfile     =       /var/run/fcron.pid
            fifofile    =       /var/run/fcron.fifo
            fcronallow  =       /etc/fcron.allow
            fcrondeny   =       /etc/fcron.deny
            shell       =       /bin/sh
            sendmail    =       /var/setuid-wrappers/sendmail
            editor      =       /run/current-system/sw/bin/vi
          '';
          target = "fcron.conf";
          mode = "0600"; # max allowed is 644
        }
      ];

    environment.systemPackages = [ pkgs.fcron ];

    security.setuidPrograms = [ "fcrontab" ];

    jobs.fcron =
      { description = "fcron daemon";

        startOn = "startup";

        after = [ "local-fs.target" ];

        environment =
          { PATH = "/run/current-system/sw/bin";
          };

        preStart =
          ''
            ${pkgs.coreutils}/bin/mkdir -m 0700 -p /var/spool/fcron
            # load system crontab file
            ${pkgs.fcron}/bin/fcrontab -u systab ${pkgs.writeText "systab" cfg.systab}
          '';

        daemonType = "fork";

        exec = "${pkgs.fcron}/sbin/fcron -m ${toString cfg.maxSerialJobs} ${queuelen}";
      };

  };

}