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}