nixos/hardware/device-tree: make overlays more reliable

This make the process of applying overlays more reliable by:

1. Ignoring dtb files that are not really device trees. [^1]

2. Adding a `filter` option (per-overlay, there already is a global one)
to limit the files to which the overlay applies. This is useful
in cases where the `compatible` string is ambiguous and multiple
unrelated files match.

Previously the script would fail in both cases.

[^1]: For example, there is dtbs/overlays/overlay_map.dtb in the
Raspberry Pi 1 kernel.

rnhmjoj 916ca8f2 802ea456

+34 -11
+10
nixos/modules/hardware/device-tree.nix
··· 14 14 ''; 15 15 }; 16 16 17 + filter = mkOption { 18 + type = types.nullOr types.str; 19 + default = null; 20 + example = "*rpi*.dtb"; 21 + description = lib.mdDoc '' 22 + Only apply to .dtb files matching glob expression. 23 + ''; 24 + }; 25 + 17 26 dtsFile = mkOption { 18 27 type = types.nullOr types.path; 19 28 description = lib.mdDoc '' ··· 165 174 ''; 166 175 type = types.listOf (types.coercedTo types.path (path: { 167 176 name = baseNameOf path; 177 + filter = null; 168 178 dtboFile = path; 169 179 }) overlayType); 170 180 description = lib.mdDoc ''
+24 -11
pkgs/os-specific/linux/device-tree/default.nix
··· 8 8 overlays = toList overlays'; 9 9 in '' 10 10 mkdir -p $out 11 - cd ${base} 11 + cd "${base}" 12 12 find . -type f -name '*.dtb' -print0 \ 13 - | xargs -0 cp -v --no-preserve=mode --target-directory $out --parents 13 + | xargs -0 cp -v --no-preserve=mode --target-directory "$out" --parents 14 14 15 - for dtb in $(find $out -type f -name '*.dtb'); do 16 - dtbCompat="$( fdtget -t s $dtb / compatible )" 15 + for dtb in $(find "$out" -type f -name '*.dtb'); do 16 + dtbCompat=$(fdtget -t s "$dtb" / compatible 2>/dev/null || true) 17 + # skip files without `compatible` string 18 + test -z "$dtbCompat" && continue 17 19 18 20 ${flip (concatMapStringsSep "\n") overlays (o: '' 19 - overlayCompat="$( fdtget -t s ${o.dtboFile} / compatible )" 20 - # overlayCompat in dtbCompat 21 - if [[ "$dtbCompat" =~ "$overlayCompat" ]]; then 22 - echo "Applying overlay ${o.name} to $( basename $dtb )" 23 - mv $dtb{,.in} 24 - fdtoverlay -o "$dtb" -i "$dtb.in" ${o.dtboFile}; 25 - rm $dtb.in 21 + overlayCompat="$(fdtget -t s "${o.dtboFile}" / compatible)" 22 + 23 + # skip incompatible and non-matching overlays 24 + if [[ ! "$dtbCompat" =~ "$overlayCompat" ]]; then 25 + echo -n "Skipping overlay ${o.name}: incompatible with $(basename "$dtb")" 26 + continue 27 + fi 28 + ${optionalString (o.filter != null) '' 29 + if [[ "''${dtb//${o.filter}/}" == "$dtb" ]]; then 30 + echo -n "Skipping overlay ${o.name}: filter does not match $(basename "$dtb")" 31 + continue 26 32 fi 33 + ''} 34 + 35 + echo -n "Applying overlay ${o.name} to $(basename "$dtb")... " 36 + mv "$dtb"{,.in} 37 + fdtoverlay -o "$dtb" -i "$dtb.in" "${o.dtboFile}" 38 + echo "ok" 39 + rm "$dtb.in" 27 40 '')} 28 41 29 42 done