| 
									
										
										
										
											2018-07-20 20:56:59 +00:00
										 |  |  | { lib, pkgs, ... }: | 
					
						
							| 
									
										
										
										
											2013-11-18 16:51:39 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-14 16:26:48 +02:00
										 |  |  | with lib; | 
					
						
							| 
									
										
										
										
											2013-11-18 16:51:39 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | let | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   makeScript = name: service: pkgs.writeScript "${name}-runner" | 
					
						
							|  |  |  |     ''
 | 
					
						
							| 
									
										
										
										
											2018-12-15 03:50:31 +00:00
										 |  |  |       #! ${pkgs.perl}/bin/perl -w -I${pkgs.perlPackages.FileSlurp}/${pkgs.perl.libPrefix} | 
					
						
							| 
									
										
										
										
											2013-11-18 16:51:39 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       use File::Slurp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       sub run { | 
					
						
							|  |  |  |           my ($cmd) = @_; | 
					
						
							|  |  |  |           my @args = split " ", $cmd; | 
					
						
							|  |  |  |           my $prog; | 
					
						
							|  |  |  |           if (substr($args[0], 0, 1) eq "@") { | 
					
						
							|  |  |  |               $prog = substr($args[0], 1); | 
					
						
							|  |  |  |               shift @args; | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |               $prog = $args[0]; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           my $pid = fork; | 
					
						
							|  |  |  |           if ($pid == 0) { | 
					
						
							|  |  |  |               setpgrp; # don't receive SIGINT etc. from terminal | 
					
						
							|  |  |  |               exec { $prog } @args; | 
					
						
							|  |  |  |               die "failed to exec $prog\n"; | 
					
						
							|  |  |  |           } elsif (!defined $pid) { | 
					
						
							|  |  |  |               die "failed to fork: $!\n"; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           return $pid; | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       sub run_wait { | 
					
						
							|  |  |  |           my ($cmd) = @_; | 
					
						
							|  |  |  |           my $pid = run $cmd; | 
					
						
							|  |  |  |           die if waitpid($pid, 0) != $pid; | 
					
						
							|  |  |  |           return $?; | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # Set the environment.  FIXME: escaping. | 
					
						
							|  |  |  |       foreach my $key (keys %ENV) { | 
					
						
							|  |  |  |           next if $key eq 'LOCALE_ARCHIVE'; | 
					
						
							|  |  |  |           delete $ENV{$key}; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       ${concatStrings (mapAttrsToList (n: v: ''
 | 
					
						
							|  |  |  |         $ENV{'${n}'} = '${v}'; | 
					
						
							|  |  |  |       '') service.environment)}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # Run the ExecStartPre program.  FIXME: this could be a list. | 
					
						
							|  |  |  |       my $preStart = '${service.serviceConfig.ExecStartPre or ""}'; | 
					
						
							|  |  |  |       if ($preStart ne "") { | 
					
						
							|  |  |  |           print STDERR "running ExecStartPre: $preStart\n"; | 
					
						
							|  |  |  |           my $res = run_wait $preStart; | 
					
						
							|  |  |  |           die "$0: ExecStartPre failed with status $res\n" if $res; | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # Run the ExecStart program. | 
					
						
							|  |  |  |       my $cmd = '${service.serviceConfig.ExecStart}'; | 
					
						
							|  |  |  |       print STDERR "running ExecStart: $cmd\n"; | 
					
						
							|  |  |  |       my $mainPid = run $cmd; | 
					
						
							|  |  |  |       $ENV{'MAINPID'} = $mainPid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # Catch SIGINT, propagate to the main program. | 
					
						
							|  |  |  |       sub intHandler { | 
					
						
							|  |  |  |           print STDERR "got SIGINT, stopping service...\n"; | 
					
						
							|  |  |  |           kill 'INT', $mainPid; | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |       $SIG{'INT'} = \&intHandler; | 
					
						
							|  |  |  |       $SIG{'QUIT'} = \&intHandler; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # Run the ExecStartPost program. | 
					
						
							|  |  |  |       my $postStart = '${service.serviceConfig.ExecStartPost or ""}'; | 
					
						
							|  |  |  |       if ($postStart ne "") { | 
					
						
							|  |  |  |           print STDERR "running ExecStartPost: $postStart\n"; | 
					
						
							|  |  |  |           my $res = run_wait $postStart; | 
					
						
							|  |  |  |           die "$0: ExecStartPost failed with status $res\n" if $res; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # Wait for the main program to exit. | 
					
						
							|  |  |  |       die if waitpid($mainPid, 0) != $mainPid; | 
					
						
							|  |  |  |       my $mainRes = $?; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # Run the ExecStopPost program. | 
					
						
							|  |  |  |       my $postStop = '${service.serviceConfig.ExecStopPost or ""}'; | 
					
						
							|  |  |  |       if ($postStop ne "") { | 
					
						
							|  |  |  |           print STDERR "running ExecStopPost: $postStop\n"; | 
					
						
							|  |  |  |           my $res = run_wait $postStop; | 
					
						
							|  |  |  |           die "$0: ExecStopPost failed with status $res\n" if $res; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       exit($mainRes & 127 ? 255 : $mainRes << 8); | 
					
						
							|  |  |  |     '';
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-26 21:44:05 +02:00
										 |  |  |   opts = { config, name, ... }: { | 
					
						
							|  |  |  |     options.runner = mkOption { | 
					
						
							|  |  |  |     internal = true; | 
					
						
							|  |  |  |     description = ''
 | 
					
						
							|  |  |  |         A script that runs the service outside of systemd, | 
					
						
							|  |  |  |         useful for testing or for using NixOS services outside | 
					
						
							|  |  |  |         of NixOS. | 
					
						
							|  |  |  |     '';
 | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     config.runner = makeScript name config; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-18 16:51:39 +01:00
										 |  |  | in | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   options = { | 
					
						
							|  |  |  |     systemd.services = mkOption { | 
					
						
							| 
									
										
										
										
											2019-01-26 21:44:05 +02:00
										 |  |  |       type = with types; attrsOf (submodule opts); | 
					
						
							| 
									
										
										
										
											2013-11-18 16:51:39 +01:00
										 |  |  |     }; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } |