xref: /dpdk/devtools/linux-uapi.sh (revision 12dc2539f7b12b2ec4570197c1e8a16a973d71f6)
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