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