1*cf97dfd1SMaxime Coquelin#!/bin/sh -e 2*cf97dfd1SMaxime Coquelin# SPDX-License-Identifier: BSD-3-Clause 3*cf97dfd1SMaxime Coquelin# Copyright (c) 2024 Red Hat, Inc. 4*cf97dfd1SMaxime Coquelin 5*cf97dfd1SMaxime Coquelin# 6*cf97dfd1SMaxime Coquelin# Import and check Linux Kernel uAPI headers 7*cf97dfd1SMaxime Coquelin# 8*cf97dfd1SMaxime Coquelin 9*cf97dfd1SMaxime Coquelinbase_url="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/" 10*cf97dfd1SMaxime Coquelinbase_path="kernel/linux/uapi/" 11*cf97dfd1SMaxime Coquelinversion="" 12*cf97dfd1SMaxime Coquelinfile="" 13*cf97dfd1SMaxime Coquelincheck_headers=0 14*cf97dfd1SMaxime Coquelinerrors=0 15*cf97dfd1SMaxime Coquelin 16*cf97dfd1SMaxime Coquelinprint_usage() 17*cf97dfd1SMaxime Coquelin{ 18*cf97dfd1SMaxime Coquelin echo "Usage: $(basename $0) [-h] [-i FILE] [-u VERSION] [-c]" 19*cf97dfd1SMaxime Coquelin echo "-i FILE import Linux header file. E.g. linux/vfio.h" 20*cf97dfd1SMaxime Coquelin echo "-u VERSION update imported list of Linux headers to a given version. E.g. v6.10" 21*cf97dfd1SMaxime Coquelin echo "-c check headers are valid" 22*cf97dfd1SMaxime Coquelin} 23*cf97dfd1SMaxime Coquelin 24*cf97dfd1SMaxime Coquelinversion_older_than() { 25*cf97dfd1SMaxime Coquelin printf '%s\n%s' "$1" "$2" | sort -C -V 26*cf97dfd1SMaxime Coquelin} 27*cf97dfd1SMaxime Coquelin 28*cf97dfd1SMaxime Coquelindownload_header() 29*cf97dfd1SMaxime Coquelin{ 30*cf97dfd1SMaxime Coquelin local header=$1 31*cf97dfd1SMaxime Coquelin local path=$2 32*cf97dfd1SMaxime Coquelin 33*cf97dfd1SMaxime Coquelin local url="${base_url}${header}?h=${version}" 34*cf97dfd1SMaxime Coquelin 35*cf97dfd1SMaxime Coquelin if ! curl -s -f --create-dirs -o $path $url; then 36*cf97dfd1SMaxime Coquelin echo "Failed to download $url" 37*cf97dfd1SMaxime Coquelin return 1 38*cf97dfd1SMaxime Coquelin fi 39*cf97dfd1SMaxime Coquelin 40*cf97dfd1SMaxime Coquelin return 0 41*cf97dfd1SMaxime Coquelin} 42*cf97dfd1SMaxime Coquelin 43*cf97dfd1SMaxime Coquelinupdate_headers() 44*cf97dfd1SMaxime Coquelin{ 45*cf97dfd1SMaxime Coquelin local header 46*cf97dfd1SMaxime Coquelin local url 47*cf97dfd1SMaxime Coquelin local path 48*cf97dfd1SMaxime Coquelin 49*cf97dfd1SMaxime Coquelin echo "Updating to $version" 50*cf97dfd1SMaxime Coquelin for filename in $(find $base_path -name "*.h" -type f); do 51*cf97dfd1SMaxime Coquelin header=${filename#$base_path} 52*cf97dfd1SMaxime Coquelin download_header $header $filename || return 1 53*cf97dfd1SMaxime Coquelin done 54*cf97dfd1SMaxime Coquelin 55*cf97dfd1SMaxime Coquelin return 0 56*cf97dfd1SMaxime Coquelin} 57*cf97dfd1SMaxime Coquelin 58*cf97dfd1SMaxime Coquelinimport_header() 59*cf97dfd1SMaxime Coquelin{ 60*cf97dfd1SMaxime Coquelin local include 61*cf97dfd1SMaxime Coquelin local import 62*cf97dfd1SMaxime Coquelin local header=$1 63*cf97dfd1SMaxime Coquelin 64*cf97dfd1SMaxime Coquelin local path="${base_path}${header}" 65*cf97dfd1SMaxime Coquelin 66*cf97dfd1SMaxime Coquelin download_header $header $path || return 1 67*cf97dfd1SMaxime Coquelin 68*cf97dfd1SMaxime Coquelin for include in $(sed -ne 's/^#include <\(.*\)>$/\1/p' $path); do 69*cf97dfd1SMaxime Coquelin if [ ! -f "${base_path}${include}" ]; then 70*cf97dfd1SMaxime Coquelin read -p "Import $include (y/n): " import && [ "$import" = 'y' ] || continue 71*cf97dfd1SMaxime Coquelin echo "Importing $include for $path" 72*cf97dfd1SMaxime Coquelin import_header "$include" || return 1 73*cf97dfd1SMaxime Coquelin fi 74*cf97dfd1SMaxime Coquelin done 75*cf97dfd1SMaxime Coquelin 76*cf97dfd1SMaxime Coquelin return 0 77*cf97dfd1SMaxime Coquelin} 78*cf97dfd1SMaxime Coquelin 79*cf97dfd1SMaxime Coquelinfixup_includes() 80*cf97dfd1SMaxime Coquelin{ 81*cf97dfd1SMaxime Coquelin local path=$1 82*cf97dfd1SMaxime Coquelin 83*cf97dfd1SMaxime Coquelin sed -i "s|^#include <linux/compiler.h>||g" $path 84*cf97dfd1SMaxime Coquelin sed -i "s|\<__user[[:space:]]||" $path 85*cf97dfd1SMaxime Coquelin 86*cf97dfd1SMaxime Coquelin # Prepend include path with "uapi/" if the header is imported 87*cf97dfd1SMaxime Coquelin for include in $(sed -ne 's/^#include <\(.*\)>$/\1/p' $path); do 88*cf97dfd1SMaxime Coquelin if [ -f "${base_path}${include}" ]; then 89*cf97dfd1SMaxime Coquelin sed -i "s|${include}|uapi/${include}|g" $path 90*cf97dfd1SMaxime Coquelin fi 91*cf97dfd1SMaxime Coquelin done 92*cf97dfd1SMaxime Coquelin} 93*cf97dfd1SMaxime Coquelin 94*cf97dfd1SMaxime Coquelincheck_header() { 95*cf97dfd1SMaxime Coquelin echo -n "Checking $1... " 96*cf97dfd1SMaxime Coquelin 97*cf97dfd1SMaxime Coquelin if ! diff -q $1 $2 >/dev/null; then 98*cf97dfd1SMaxime Coquelin echo "KO" 99*cf97dfd1SMaxime Coquelin diff -u $1 $2 100*cf97dfd1SMaxime Coquelin return 1 101*cf97dfd1SMaxime Coquelin else 102*cf97dfd1SMaxime Coquelin echo "OK" 103*cf97dfd1SMaxime Coquelin fi 104*cf97dfd1SMaxime Coquelin 105*cf97dfd1SMaxime Coquelin return 0 106*cf97dfd1SMaxime Coquelin} 107*cf97dfd1SMaxime Coquelin 108*cf97dfd1SMaxime Coquelinwhile getopts i:u:ch opt ; do 109*cf97dfd1SMaxime Coquelin case ${opt} in 110*cf97dfd1SMaxime Coquelin i ) file=$OPTARG ;; 111*cf97dfd1SMaxime Coquelin u ) version=$OPTARG ;; 112*cf97dfd1SMaxime Coquelin c ) check_headers=1 ;; 113*cf97dfd1SMaxime Coquelin h ) print_usage ; exit 0 ;; 114*cf97dfd1SMaxime Coquelin ? ) print_usage ; exit 1 ;; 115*cf97dfd1SMaxime Coquelin esac 116*cf97dfd1SMaxime Coquelindone 117*cf97dfd1SMaxime Coquelin 118*cf97dfd1SMaxime Coquelinshift $(($OPTIND - 1)) 119*cf97dfd1SMaxime Coquelinif [ $# -ne 0 ]; then 120*cf97dfd1SMaxime Coquelin print_usage 121*cf97dfd1SMaxime Coquelin exit 1 122*cf97dfd1SMaxime Coquelinfi 123*cf97dfd1SMaxime Coquelin 124*cf97dfd1SMaxime Coquelincd $(dirname $0)/.. 125*cf97dfd1SMaxime Coquelin 126*cf97dfd1SMaxime Coquelincurrent_version=$(< ${base_path}/version) 127*cf97dfd1SMaxime Coquelin 128*cf97dfd1SMaxime Coquelinif [ -n "${version}" ]; then 129*cf97dfd1SMaxime Coquelin if version_older_than "$version" "$current_version"; then 130*cf97dfd1SMaxime Coquelin echo "Headers already up to date ($current_version >= $version)" 131*cf97dfd1SMaxime Coquelin version=$current_version 132*cf97dfd1SMaxime Coquelin else 133*cf97dfd1SMaxime Coquelin update_headers || exit 1 134*cf97dfd1SMaxime Coquelin fi 135*cf97dfd1SMaxime Coquelinelse 136*cf97dfd1SMaxime Coquelin echo "Version not specified, using current version ($current_version)" 137*cf97dfd1SMaxime Coquelin version=$current_version 138*cf97dfd1SMaxime Coquelinfi 139*cf97dfd1SMaxime Coquelin 140*cf97dfd1SMaxime Coquelinif [ -n "${file}" ]; then 141*cf97dfd1SMaxime Coquelin import_header $file || exit 1 142*cf97dfd1SMaxime Coquelinfi 143*cf97dfd1SMaxime Coquelin 144*cf97dfd1SMaxime Coquelinfor filename in $(find $base_path -name "*.h" -type f); do 145*cf97dfd1SMaxime Coquelin fixup_includes $filename || exit 1 146*cf97dfd1SMaxime Coquelindone 147*cf97dfd1SMaxime Coquelin 148*cf97dfd1SMaxime Coquelinecho $version > ${base_path}/version 149*cf97dfd1SMaxime Coquelin 150*cf97dfd1SMaxime Coquelinif [ $check_headers -eq 0 ]; then 151*cf97dfd1SMaxime Coquelin exit 0 152*cf97dfd1SMaxime Coquelinfi 153*cf97dfd1SMaxime Coquelin 154*cf97dfd1SMaxime Coquelintmpheader="$(mktemp -t dpdk.checkuapi.XXXXXX)" 155*cf97dfd1SMaxime Coquelintrap "rm -f '$tmpheader'" INT 156*cf97dfd1SMaxime Coquelin 157*cf97dfd1SMaxime Coquelinecho "Checking imported headers for version ${version}" 158*cf97dfd1SMaxime Coquelin 159*cf97dfd1SMaxime Coquelinfor filename in $(find $base_path -name "*.h" -type f); do 160*cf97dfd1SMaxime Coquelin header=${filename#$base_path} 161*cf97dfd1SMaxime Coquelin download_header $header $tmpheader || exit 1 162*cf97dfd1SMaxime Coquelin fixup_includes $tmpheader || exit 1 163*cf97dfd1SMaxime Coquelin check_header $filename $tmpheader || errors=$((errors+1)) 164*cf97dfd1SMaxime Coquelindone 165*cf97dfd1SMaxime Coquelin 166*cf97dfd1SMaxime Coquelinecho "$errors error(s) found" 167*cf97dfd1SMaxime Coquelin 168*cf97dfd1SMaxime Coquelinrm -f $tmpheader 169*cf97dfd1SMaxime Coquelintrap - INT 170*cf97dfd1SMaxime Coquelin 171*cf97dfd1SMaxime Coquelinexit $errors 172