1#!/usr/bin/env bash
2set -e
3
4# Add hash files for packages with custom versions for
5# BR2_DOWNLOAD_FORCE_CHECK_HASHES=y
6#
7# Run in a configured Buildroot directory, E.G.
8# make foo_defconfig; ./utils/add-custom-hashes
9
10# print BR-style message
11# message <info message>
12message() {
13    tput smso 2>/dev/null
14    echo "$*"
15    tput rmso 2>/dev/null
16}
17
18# print error message and exit
19# die <error message>
20die() {
21    echo "Error: $*" >&2
22    exit 1
23}
24
25# get package(s) for download file, if any
26# get_pkgs <json> <file>
27get_pkgs() {
28    jq --arg file "$2" -r \
29       'to_entries[] | select(.value.downloads[0].source == $file) | .key | strings' "$1"
30}
31
32# get download dir for package
33# get_pkg_dl_dir <json> <package>
34get_pkg_dl_dir() {
35    jq --arg pkg "$2" -r '.[$pkg].dl_dir | strings' "$1"
36}
37
38# generate hash file for download file
39# gen_hash <dir> <file>
40gen_hash() {
41    (
42        cd "$1" && printf '# Locally calculated\nsha256  ' && sha256sum "$2"
43    )
44}
45
46command -v jq >/dev/null || die 'Script needs jq'
47
48[ -e .config ] || \
49  die "No .config found, please run this in a configured Buildroot (O=) directory"
50
51message Collecting data
52
53eval "$(make -s VARS='TOPDIR DL_DIR BR_NO_CHECK_HASH_FOR BR2_GLOBAL_PATCH_DIR' QUOTED_VARS=YES printvars)"
54# global patch dir may already have quotes
55BR2_GLOBAL_PATCH_DIR=$(echo "$BR2_GLOBAL_PATCH_DIR" | tr -d '"')
56
57[ -n "$BR2_GLOBAL_PATCH_DIR" ] || die "No BR2_GLOBAL_PATCH_DIR defined, nothing to do"
58[ -n "$BR_NO_CHECK_HASH_FOR" ] || die "No packages without hashes found, nothing to do"
59
60[ -d "$TOPDIR" ] || die "TOPDIR ($TOPDIR) does not look correct"
61[ -d "$DL_DIR" ] || die "DL_DIR ($DL_DIR) does not look correct"
62
63# patch dir may contain multiple dirs, use the last one
64# shellcheck disable=SC2086 # we need the word splitting
65set -- $BR2_GLOBAL_PATCH_DIR
66if [ $# -gt 1 ]; then
67    BR2_GLOBAL_PATCH_DIR="${!#}";
68    message BR2_GLOBAL_PATCH_DIR contains multiple directories, using "$BR2_GLOBAL_PATCH_DIR"
69fi
70
71# patch dir may be relative to TOPDIR
72case "$BR2_GLOBAL_PATCH_DIR" in
73    /*) ;;
74    *) BR2_GLOBAL_PATCH_DIR="$TOPDIR/$BR2_GLOBAL_PATCH_DIR"
75       ;;
76esac
77
78[ -d "$BR2_GLOBAL_PATCH_DIR" ] \
79  || die "BR2_GLOBAL_PATCH_DIR ($BR2_GLOBAL_PATCH_DIR) does not look correct"
80
81trap 'rm -f "$JSON"' EXIT
82JSON=$(mktemp)
83make show-info > "$JSON"
84
85# ensure files have been downloaded, but without checking
86make BR2_DOWNLOAD_FORCE_CHECK_HASHES= source
87
88message Updating hashes
89
90for file in $BR_NO_CHECK_HASH_FOR; do
91    for pkg in $(get_pkgs "$JSON" "$file"); do
92        HASHFILE="$BR2_GLOBAL_PATCH_DIR/$pkg/$pkg.hash"
93        PKG_DL_DIR=$(get_pkg_dl_dir "$JSON" "$pkg")
94        message "Adding hash for $file to $HASHFILE"
95        mkdir -p "${HASHFILE%/*}"
96        gen_hash "$DL_DIR/$PKG_DL_DIR" "$file" > "$HASHFILE"
97    done
98done
99
100# Symlink linux-headers to linux if identical
101linux_hash="$BR2_GLOBAL_PATCH_DIR/linux/linux.hash"
102linux_headers_hash="$BR2_GLOBAL_PATCH_DIR/linux-headers/linux-headers.hash"
103if [ -e "$linux_hash" ] && [ -e "$linux_headers_hash" ] \
104    && cmp -s "$linux_hash" "$linux_headers_hash"; then
105    ln -sf ../linux/linux.hash "$linux_headers_hash"
106fi
107
108message Verifying hashes
109
110make clean
111make BR2_DOWNLOAD_FORCE_CHECK_HASHES=y source
112