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