at 16.09-beta 6.1 kB view raw
1{ config, lib, pkgs }: 2 3with lib; 4 5let cfg = config.systemd; in 6 7rec { 8 9 shellEscape = s: (replaceChars [ "\\" ] [ "\\\\" ] s); 10 11 makeUnit = name: unit: 12 let 13 pathSafeName = lib.replaceChars ["@" ":" "\\"] ["-" "-" "-"] name; 14 in 15 if unit.enable then 16 pkgs.runCommand "unit-${pathSafeName}" 17 { preferLocalBuild = true; 18 allowSubstitutes = false; 19 inherit (unit) text; 20 } 21 '' 22 mkdir -p $out 23 echo -n "$text" > $out/${shellEscape name} 24 '' 25 else 26 pkgs.runCommand "unit-${pathSafeName}-disabled" 27 { preferLocalBuild = true; 28 allowSubstitutes = false; 29 } 30 '' 31 mkdir -p $out 32 ln -s /dev/null $out/${shellEscape name} 33 ''; 34 35 boolValues = [true false "yes" "no"]; 36 37 digits = map toString (range 0 9); 38 39 isByteFormat = s: 40 let 41 l = reverseList (stringToCharacters s); 42 suffix = head l; 43 nums = tail l; 44 in elem suffix (["K" "M" "G" "T"] ++ digits) 45 && all (num: elem num digits) nums; 46 47 assertByteFormat = name: group: attr: 48 optional (attr ? ${name} && ! isByteFormat attr.${name}) 49 "Systemd ${group} field `${name}' must be in byte format [0-9]+[KMGT]."; 50 51 hexChars = stringToCharacters "0123456789abcdefABCDEF"; 52 53 isMacAddress = s: stringLength s == 17 54 && flip all (splitString ":" s) (bytes: 55 all (byte: elem byte hexChars) (stringToCharacters bytes) 56 ); 57 58 assertMacAddress = name: group: attr: 59 optional (attr ? ${name} && ! isMacAddress attr.${name}) 60 "Systemd ${group} field `${name}' must be a valid mac address."; 61 62 63 assertValueOneOf = name: values: group: attr: 64 optional (attr ? ${name} && !elem attr.${name} values) 65 "Systemd ${group} field `${name}' cannot have value `${attr.${name}}'."; 66 67 assertHasField = name: group: attr: 68 optional (!(attr ? ${name})) 69 "Systemd ${group} field `${name}' must exist."; 70 71 assertRange = name: min: max: group: attr: 72 optional (attr ? ${name} && !(min <= attr.${name} && max >= attr.${name})) 73 "Systemd ${group} field `${name}' is outside the range [${toString min},${toString max}]"; 74 75 assertOnlyFields = fields: group: attr: 76 let badFields = filter (name: ! elem name fields) (attrNames attr); in 77 optional (badFields != [ ]) 78 "Systemd ${group} has extra fields [${concatStringsSep " " badFields}]."; 79 80 checkUnitConfig = group: checks: v: 81 let errors = concatMap (c: c group v) checks; in 82 if errors == [] then true 83 else builtins.trace (concatStringsSep "\n" errors) false; 84 85 toOption = x: 86 if x == true then "true" 87 else if x == false then "false" 88 else toString x; 89 90 attrsToSection = as: 91 concatStrings (concatLists (mapAttrsToList (name: value: 92 map (x: '' 93 ${name}=${toOption x} 94 '') 95 (if isList value then value else [value])) 96 as)); 97 98 generateUnits = type: units: upstreamUnits: upstreamWants: 99 pkgs.runCommand "${type}-units" 100 { preferLocalBuild = true; 101 allowSubstitutes = false; 102 } '' 103 mkdir -p $out 104 105 # Copy the upstream systemd units we're interested in. 106 for i in ${toString upstreamUnits}; do 107 fn=${cfg.package}/example/systemd/${type}/$i 108 if ! [ -e $fn ]; then echo "missing $fn"; false; fi 109 if [ -L $fn ]; then 110 target="$(readlink "$fn")" 111 if [ ''${target:0:3} = ../ ]; then 112 ln -s "$(readlink -f "$fn")" $out/ 113 else 114 cp -pd $fn $out/ 115 fi 116 else 117 ln -s $fn $out/ 118 fi 119 done 120 121 # Copy .wants links, but only those that point to units that 122 # we're interested in. 123 for i in ${toString upstreamWants}; do 124 fn=${cfg.package}/example/systemd/${type}/$i 125 if ! [ -e $fn ]; then echo "missing $fn"; false; fi 126 x=$out/$(basename $fn) 127 mkdir $x 128 for i in $fn/*; do 129 y=$x/$(basename $i) 130 cp -pd $i $y 131 if ! [ -e $y ]; then rm $y; fi 132 done 133 done 134 135 # Symlink all units provided listed in systemd.packages. 136 for i in ${toString cfg.packages}; do 137 for fn in $i/etc/systemd/${type}/* $i/lib/systemd/${type}/*; do 138 if ! [[ "$fn" =~ .wants$ ]]; then 139 ln -s $fn $out/ 140 fi 141 done 142 done 143 144 # Symlink all units defined by systemd.units. If these are also 145 # provided by systemd or systemd.packages, then add them as 146 # <unit-name>.d/overrides.conf, which makes them extend the 147 # upstream unit. 148 for i in ${toString (mapAttrsToList (n: v: v.unit) units)}; do 149 fn=$(basename $i/*) 150 if [ -e $out/$fn ]; then 151 if [ "$(readlink -f $i/$fn)" = /dev/null ]; then 152 ln -sfn /dev/null $out/$fn 153 else 154 mkdir $out/$fn.d 155 ln -s $i/$fn $out/$fn.d/overrides.conf 156 fi 157 else 158 ln -fs $i/$fn $out/ 159 fi 160 done 161 162 # Created .wants and .requires symlinks from the wantedBy and 163 # requiredBy options. 164 ${concatStrings (mapAttrsToList (name: unit: 165 concatMapStrings (name2: '' 166 mkdir -p $out/'${name2}.wants' 167 ln -sfn '../${name}' $out/'${name2}.wants'/ 168 '') unit.wantedBy) units)} 169 170 ${concatStrings (mapAttrsToList (name: unit: 171 concatMapStrings (name2: '' 172 mkdir -p $out/'${name2}.requires' 173 ln -sfn '../${name}' $out/'${name2}.requires'/ 174 '') unit.requiredBy) units)} 175 176 ${optionalString (type == "system") '' 177 # Stupid misc. symlinks. 178 ln -s ${cfg.defaultUnit} $out/default.target 179 ln -s ${cfg.ctrlAltDelUnit} $out/ctrl-alt-del.target 180 ln -s rescue.target $out/kbrequest.target 181 182 mkdir -p $out/getty.target.wants/ 183 ln -s ../autovt@tty1.service $out/getty.target.wants/ 184 185 ln -s ../local-fs.target ../remote-fs.target ../network.target \ 186 ../nss-lookup.target ../nss-user-lookup.target ../swap.target \ 187 $out/multi-user.target.wants/ 188 ''} 189 ''; # */ 190 191}