default.nix (8910B)
1 { 2 config, 3 pkgs, 4 lib, 5 lim, 6 ... 7 }: 8 let 9 inherit (pkgs) 10 execline 11 s6 12 s6-init-bin 13 s6-linux-init 14 stdenvNoCC 15 ; 16 inherit (lib.lists) unique concatMap; 17 inherit (lib) concatStrings; 18 inherit (builtins) map; 19 inherit (pkgs.pseudofile) dir symlink; 20 inherit (pkgs.liminix.services) oneshot bundle longrun; 21 inherit (lib) 22 mkIf 23 mkEnableOption 24 mkOption 25 types 26 ; 27 cfg = config.logging; 28 29 logger = 30 let 31 pipecmds = 32 [ "${s6}/bin/s6-log -bpd3 -- ${cfg.script} 1" ] 33 ++ (lib.optional (cfg ? persistent && cfg.persistent.enable) "/bin/tee /dev/pmsg0") 34 ++ (lib.optional cfg.shipping.enable "${pkgs.logshipper}/bin/logtap ${cfg.shipping.socket} logshipper-socket-event"); 35 in 36 '' 37 #!${execline}/bin/execlineb -P 38 ${execline}/bin/redirfd -w 1 /dev/null 39 ${execline}/bin/redirfd -rnb 0 fifo 40 ${concatStrings (map (l: "pipeline { ${l} }\n") pipecmds)} 41 ${s6}/bin/s6-log -- ${cfg.directory} 42 ''; 43 s6-rc-db = 44 let 45 # In the default bundle we need to have all the services 46 # in config.services except for controlled services and 47 # anything that depends on one. But we do need the controllers 48 # themselves. 49 50 # So, find all required services and their transitive 51 # dependencies and their controllers. remove all controlled 52 # services and all services that have a controlled service as 53 # dependency 54 55 isControlled = s: s ? controller && s.controller != null; 56 deps = s: s.dependencies ++ lib.optional (isControlled s) s.controller; 57 flatDeps = s: [ s ] ++ concatMap flatDeps (deps s); 58 allServices = unique (concatMap flatDeps (builtins.attrValues config.services)); 59 isDependentOnControlled = 60 s: isControlled s || (lib.lists.any isDependentOnControlled s.dependencies); 61 62 # all controlled services depend on this oneshot, which 63 # makes a list of them so we can identify them at runtime 64 controlled = oneshot { 65 name = "controlled"; 66 up = '' 67 mkdir -p /run/services/controlled 68 for s in $(s6-rc-db -d dependencies controlled); do 69 touch /run/services/controlled/$s 70 done 71 ''; 72 down = "rm -r /run/services/controlled"; 73 }; 74 75 defaultStart = builtins.filter (s: !(isDependentOnControlled s)) allServices; 76 defaultDefaultTarget = bundle { 77 name = "default"; 78 contents = defaultStart ++ [ controlled ]; 79 }; 80 servicesAttrs = { 81 default = defaultDefaultTarget; 82 } // config.services; 83 in 84 pkgs.s6-rc-database.override { 85 services = builtins.attrValues servicesAttrs; 86 }; 87 s6-init-scripts = stdenvNoCC.mkDerivation { 88 name = "s6-scripts"; 89 src = ./scripts; 90 phases = [ 91 "unpackPhase" 92 "installPhase" 93 ]; 94 buildInputs = [ ]; 95 installPhase = '' 96 mkdir $out 97 cp -r $src $out/scripts 98 chmod -R +w $out 99 ''; 100 }; 101 service = dir { 102 s6-linux-init-runleveld = dir { 103 notification-fd = { 104 file = "3"; 105 }; 106 run = { 107 file = '' 108 #!${execline}/bin/execlineb -P 109 ${execline}/bin/fdmove -c 2 1 110 ${execline}/bin/fdmove 1 3 111 ${s6}/bin/s6-ipcserver -1 -a 0700 -c 1 -- s 112 ${s6}/bin/s6-sudod -dt30000 -- "/etc/s6-linux-init/current"/scripts/runlevel 113 ''; 114 mode = "0755"; 115 }; 116 }; 117 s6-linux-init-shutdownd = dir { 118 fifo = { 119 type = "i"; 120 mode = "0600"; 121 }; 122 run = { 123 file = '' 124 #!${execline}/bin/execlineb -P 125 importas PATH PATH 126 export PATH ${s6}/bin:''${PATH} 127 foreground { echo path is ''${PATH} } 128 ${s6-linux-init}/bin/s6-linux-init-shutdownd -c "/etc/s6-linux-init/current" -g 3000 129 ''; 130 mode = "0755"; 131 }; 132 }; 133 s6-svscan-log = dir { 134 fifo = { 135 type = "i"; 136 mode = "0600"; 137 }; 138 notification-fd = { 139 file = "3"; 140 }; 141 run = { 142 file = logger; 143 mode = "0755"; 144 }; 145 }; 146 getty = dir { 147 run = { 148 # We can't run a useful shell on /dev/console because 149 # /dev/console is not allowed to be the controlling 150 # tty of any process, which means ^C ^Z etc don't work. 151 # So we work out what the *actual* console device is 152 # using sysfs and open our shell there instead. 153 file = '' 154 #!${execline}/bin/execlineb -P 155 ${execline}/bin/cd / 156 redirfd -r 0 /sys/devices/virtual/tty/console/active 157 withstdinas CONSOLETTY 158 importas CONSOLETTY CONSOLETTY 159 redirfd -w 2 /dev/''${CONSOLETTY} 160 fdmove -c 1 2 161 redirfd -r 0 /dev/''${CONSOLETTY} 162 /bin/ash -l 163 ''; 164 mode = "0755"; 165 }; 166 down-signal = { 167 file = "HUP\n"; 168 }; 169 }; 170 ".s6-svscan" = 171 let 172 openConsole = '' 173 #!${execline}/bin/execlineb -P 174 ${execline}/bin/redirfd -w 2 /dev/console 175 ${execline}/bin/fdmove -c 1 2 176 ''; 177 quit = message: '' 178 ${openConsole} 179 ${execline}/bin/foreground { ${s6-linux-init}/bin/s6-linux-init-echo -- ${message} } 180 ${s6-linux-init}/bin/s6-linux-init-hpr -fr 181 ''; 182 shutdown = action: '' 183 #!${execline}/bin/execlineb -P 184 ${s6-linux-init}/bin/s6-linux-init-shutdown -a #{action} -- now 185 ''; 186 empty = "#!${execline}/bin/execlineb -P\n"; 187 in 188 dir { 189 crash = { 190 file = quit "s6-svscan crashed. Rebooting."; 191 mode = "0755"; 192 }; 193 finish = { 194 file = '' 195 ${openConsole} 196 ifelse { test -x /run/maintenance/exec } { /run/maintenance/exec } 197 foreground { echo "s6-svscan exited. Rebooting." } 198 wait { } 199 ${s6-linux-init}/bin/s6-linux-init-hpr -fr 200 ''; 201 mode = "0755"; 202 }; 203 SIGINT = { 204 file = shutdown "-r"; 205 mode = "0755"; 206 }; 207 SIGPWR = { 208 file = shutdown "-p"; 209 mode = "0755"; 210 }; 211 SIGQUIT = { 212 file = empty; 213 mode = "0755"; 214 }; 215 SIGTERM = { 216 file = empty; 217 mode = "0755"; 218 }; 219 SIGUSR1 = { 220 file = shutdown "-p"; 221 mode = "0755"; 222 }; 223 SIGUSR2 = { 224 file = shutdown "-h"; 225 mode = "0755"; 226 }; 227 SIGWINCH = { 228 file = empty; 229 mode = "0755"; 230 }; 231 232 }; 233 }; 234 in 235 { 236 options = { 237 logging = { 238 shipping = { 239 enable = mkEnableOption "unix socket for log shipping"; 240 socket = mkOption { 241 description = "socket pathname"; 242 type = types.path; 243 default = "/run/.log-shipping.sock"; 244 }; 245 service = mkOption { 246 description = "log shipper service"; 247 type = pkgs.liminix.lib.types.service; 248 }; 249 }; 250 script = mkOption { 251 description = "\"log script\" used by fallback s6-log process"; 252 type = types.str; 253 default = "p${config.hostname} t"; 254 }; 255 directory = mkOption { 256 description = "default log directory"; 257 default = "/run/log"; 258 type = types.path; 259 }; 260 }; 261 }; 262 imports = [ 263 ( 264 { 265 config, 266 pkgs, 267 lib, 268 ... 269 }: 270 let 271 cfg = config.logging; 272 pipeline = 273 shipper: 274 bundle { 275 name = "log-shipping-pipe"; 276 contents = 277 let 278 eat = longrun { 279 name = "log-shipping-pipe-eat"; 280 run = '' 281 fdmove -c 12 1 \ 282 ${pkgs.s6}/bin/s6-ipcserver ${cfg.shipping.socket} \ 283 fdmove -c 1 12 \ 284 cat 285 ''; 286 producer-for = spew.name; 287 }; 288 spew = shipper.override { 289 consumer-for = "log-shipping-pipe-eat"; 290 }; 291 in 292 [ 293 eat 294 spew 295 ]; 296 }; 297 in 298 mkIf cfg.shipping.enable { 299 services.${cfg.shipping.service.name} = pipeline cfg.shipping.service; 300 } 301 ) 302 ]; 303 304 config = { 305 filesystem = dir { 306 etc = dir { 307 s6-rc = dir { 308 compiled = symlink "${s6-rc-db}/compiled"; 309 }; 310 s6-linux-init = dir { 311 current = dir { 312 scripts = symlink "${s6-init-scripts}/scripts"; 313 env = dir { }; 314 run-image = dir { 315 uncaught-logs = (dir { }) // { 316 mode = "2750"; 317 }; 318 inherit service; 319 }; 320 }; 321 }; 322 }; 323 bin = dir { 324 init = symlink "${s6-init-bin}/bin/init"; 325 }; 326 }; 327 }; 328 }