12bfe3f2eSlogwang#! /bin/sh 2d30ea906Sjfb8856606# SPDX-License-Identifier: BSD-3-Clause 32bfe3f2eSlogwang# Copyright 2015 6WIND S.A. 42bfe3f2eSlogwang 52bfe3f2eSlogwang# Load config options: 62bfe3f2eSlogwang# - DPDK_CHECKPATCH_PATH 74418919fSjohnjiang# - DPDK_CHECKPATCH_CODESPELL 82bfe3f2eSlogwang# - DPDK_CHECKPATCH_LINE_LENGTH 94418919fSjohnjiang# - DPDK_CHECKPATCH_OPTIONS 104418919fSjohnjiang. $(dirname $(readlink -f $0))/load-devel-config 112bfe3f2eSlogwang 124418919fSjohnjiangVALIDATE_NEW_API=$(dirname $(readlink -f $0))/check-symbol-change.sh 13d30ea906Sjfb8856606 144418919fSjohnjiang# Enable codespell by default. This can be overwritten from a config file. 154418919fSjohnjiang# Codespell can also be enabled by setting DPDK_CHECKPATCH_CODESPELL to a valid path 164418919fSjohnjiang# to a dictionary.txt file if dictionary.txt is not in the default location. 174418919fSjohnjiangcodespell=${DPDK_CHECKPATCH_CODESPELL:-enable} 182bfe3f2eSlogwanglength=${DPDK_CHECKPATCH_LINE_LENGTH:-80} 192bfe3f2eSlogwang 202bfe3f2eSlogwang# override default Linux options 212bfe3f2eSlogwangoptions="--no-tree" 224418919fSjohnjiangif [ "$codespell" = "enable" ] ; then 234418919fSjohnjiang options="$options --codespell" 244418919fSjohnjiangelif [ -f "$codespell" ] ; then 254418919fSjohnjiang options="$options --codespell" 264418919fSjohnjiang options="$options --codespellfile $codespell" 274418919fSjohnjiangfi 282bfe3f2eSlogwangoptions="$options --max-line-length=$length" 292bfe3f2eSlogwangoptions="$options --show-types" 30*2d9fd380Sjfb8856606options="$options --ignore=LINUX_VERSION_CODE,ENOSYS,\ 31d30ea906Sjfb8856606FILE_PATH_CHANGES,MAINTAINERS_STYLE,SPDX_LICENSE_TAG,\ 322bfe3f2eSlogwangVOLATILE,PREFER_PACKED,PREFER_ALIGNED,PREFER_PRINTF,\ 33*2d9fd380Sjfb8856606PREFER_KERNEL_TYPES,PREFER_FALLTHROUGH,BIT_MACRO,CONST_STRUCT,\ 34*2d9fd380Sjfb8856606SPLIT_STRING,LONG_LINE_STRING,C99_COMMENT_TOLERANCE,\ 352bfe3f2eSlogwangLINE_SPACING,PARENTHESIS_ALIGNMENT,NETWORKING_BLOCK_COMMENT_STYLE,\ 362bfe3f2eSlogwangNEW_TYPEDEFS,COMPARISON_TO_NULL" 374418919fSjohnjiangoptions="$options $DPDK_CHECKPATCH_OPTIONS" 38d30ea906Sjfb8856606 392bfe3f2eSlogwangprint_usage () { 402bfe3f2eSlogwang cat <<- END_OF_HELP 41*2d9fd380Sjfb8856606 usage: $(basename $0) [-h] [-q] [-v] [-nX|-r range|patch1 [patch2] ...] 422bfe3f2eSlogwang 432bfe3f2eSlogwang Run Linux kernel checkpatch.pl with DPDK options. 442bfe3f2eSlogwang The environment variable DPDK_CHECKPATCH_PATH must be set. 452bfe3f2eSlogwang 462bfe3f2eSlogwang The patches to check can be from stdin, files specified on the command line, 474418919fSjohnjiang latest git commits limited with -n option, or commits in the git range 48*2d9fd380Sjfb8856606 specified with -r option (default: "origin/main.."). 492bfe3f2eSlogwang END_OF_HELP 502bfe3f2eSlogwang} 512bfe3f2eSlogwang 52d30ea906Sjfb8856606check_forbidden_additions() { # <patch> 531646932aSjfb8856606 res=0 541646932aSjfb8856606 55d30ea906Sjfb8856606 # refrain from new additions of rte_panic() and rte_exit() 56d30ea906Sjfb8856606 # multiple folders and expressions are separated by spaces 57d30ea906Sjfb8856606 awk -v FOLDERS="lib drivers" \ 58d30ea906Sjfb8856606 -v EXPRESSIONS="rte_panic\\\( rte_exit\\\(" \ 59d30ea906Sjfb8856606 -v RET_ON_FAIL=1 \ 60d30ea906Sjfb8856606 -v MESSAGE='Using rte_panic/rte_exit' \ 614418919fSjohnjiang -f $(dirname $(readlink -f $0))/check-forbidden-tokens.awk \ 621646932aSjfb8856606 "$1" || res=1 631646932aSjfb8856606 64*2d9fd380Sjfb8856606 # refrain from using compiler attribute without defining a common macro 65*2d9fd380Sjfb8856606 awk -v FOLDERS="lib drivers app examples" \ 66*2d9fd380Sjfb8856606 -v EXPRESSIONS="__attribute__" \ 67*2d9fd380Sjfb8856606 -v RET_ON_FAIL=1 \ 68*2d9fd380Sjfb8856606 -v MESSAGE='Using compiler attribute directly' \ 69*2d9fd380Sjfb8856606 -f $(dirname $(readlink -f $0))/check-forbidden-tokens.awk \ 70*2d9fd380Sjfb8856606 "$1" || res=1 71*2d9fd380Sjfb8856606 72*2d9fd380Sjfb8856606 # forbid variable declaration inside "for" loop 73*2d9fd380Sjfb8856606 awk -v FOLDERS='.' \ 74*2d9fd380Sjfb8856606 -v EXPRESSIONS='for[[:space:]]*\\((char|u?int|unsigned|s?size_t)' \ 75*2d9fd380Sjfb8856606 -v RET_ON_FAIL=1 \ 76*2d9fd380Sjfb8856606 -v MESSAGE='Declaring a variable inside for()' \ 77*2d9fd380Sjfb8856606 -f $(dirname $(readlink -f $0))/check-forbidden-tokens.awk \ 78*2d9fd380Sjfb8856606 "$1" || res=1 79*2d9fd380Sjfb8856606 80*2d9fd380Sjfb8856606 # refrain from new additions of 16/32/64 bits rte_atomicNN_xxx() 81*2d9fd380Sjfb8856606 awk -v FOLDERS="lib drivers app examples" \ 82*2d9fd380Sjfb8856606 -v EXPRESSIONS="rte_atomic[0-9][0-9]_.*\\\(" \ 83*2d9fd380Sjfb8856606 -v RET_ON_FAIL=1 \ 84*2d9fd380Sjfb8856606 -v MESSAGE='Using rte_atomicNN_xxx' \ 85*2d9fd380Sjfb8856606 -f $(dirname $(readlink -f $0))/check-forbidden-tokens.awk \ 86*2d9fd380Sjfb8856606 "$1" || res=1 87*2d9fd380Sjfb8856606 88*2d9fd380Sjfb8856606 # refrain from new additions of rte_smp_[r/w]mb() 89*2d9fd380Sjfb8856606 awk -v FOLDERS="lib drivers app examples" \ 90*2d9fd380Sjfb8856606 -v EXPRESSIONS="rte_smp_(r|w)?mb\\\(" \ 91*2d9fd380Sjfb8856606 -v RET_ON_FAIL=1 \ 92*2d9fd380Sjfb8856606 -v MESSAGE='Using rte_smp_[r/w]mb' \ 93*2d9fd380Sjfb8856606 -f $(dirname $(readlink -f $0))/check-forbidden-tokens.awk \ 94*2d9fd380Sjfb8856606 "$1" || res=1 95*2d9fd380Sjfb8856606 96*2d9fd380Sjfb8856606 # refrain from using compiler __sync_xxx builtins 97*2d9fd380Sjfb8856606 awk -v FOLDERS="lib drivers app examples" \ 98*2d9fd380Sjfb8856606 -v EXPRESSIONS="__sync_.*\\\(" \ 99*2d9fd380Sjfb8856606 -v RET_ON_FAIL=1 \ 100*2d9fd380Sjfb8856606 -v MESSAGE='Using __sync_xxx builtins' \ 101*2d9fd380Sjfb8856606 -f $(dirname $(readlink -f $0))/check-forbidden-tokens.awk \ 102*2d9fd380Sjfb8856606 "$1" || res=1 103*2d9fd380Sjfb8856606 104*2d9fd380Sjfb8856606 # refrain from using compiler __atomic_thread_fence() 105*2d9fd380Sjfb8856606 # It should be avoided on x86 for SMP case. 106*2d9fd380Sjfb8856606 awk -v FOLDERS="lib drivers app examples" \ 107*2d9fd380Sjfb8856606 -v EXPRESSIONS="__atomic_thread_fence\\\(" \ 108*2d9fd380Sjfb8856606 -v RET_ON_FAIL=1 \ 109*2d9fd380Sjfb8856606 -v MESSAGE='Using __atomic_thread_fence' \ 110*2d9fd380Sjfb8856606 -f $(dirname $(readlink -f $0))/check-forbidden-tokens.awk \ 111*2d9fd380Sjfb8856606 "$1" || res=1 112*2d9fd380Sjfb8856606 113*2d9fd380Sjfb8856606 # forbid use of experimental build flag except in examples 114*2d9fd380Sjfb8856606 awk -v FOLDERS='lib drivers app' \ 115*2d9fd380Sjfb8856606 -v EXPRESSIONS='-DALLOW_EXPERIMENTAL_API allow_experimental_apis' \ 116*2d9fd380Sjfb8856606 -v RET_ON_FAIL=1 \ 117*2d9fd380Sjfb8856606 -v MESSAGE='Using experimental build flag for in-tree compilation' \ 118*2d9fd380Sjfb8856606 -f $(dirname $(readlink -f $0))/check-forbidden-tokens.awk \ 119*2d9fd380Sjfb8856606 "$1" || res=1 120*2d9fd380Sjfb8856606 121d30ea906Sjfb8856606 # svg figures must be included with wildcard extension 122d30ea906Sjfb8856606 # because of png conversion for pdf docs 123d30ea906Sjfb8856606 awk -v FOLDERS='doc' \ 124d30ea906Sjfb8856606 -v EXPRESSIONS='::[[:space:]]*[^[:space:]]*\\.svg' \ 125d30ea906Sjfb8856606 -v RET_ON_FAIL=1 \ 126d30ea906Sjfb8856606 -v MESSAGE='Using explicit .svg extension instead of .*' \ 1274418919fSjohnjiang -f $(dirname $(readlink -f $0))/check-forbidden-tokens.awk \ 1281646932aSjfb8856606 "$1" || res=1 1291646932aSjfb8856606 1300c6bd470Sfengbojiang # links must prefer https over http 1310c6bd470Sfengbojiang awk -v FOLDERS='doc' \ 1320c6bd470Sfengbojiang -v EXPRESSIONS='http://.*dpdk.org' \ 1330c6bd470Sfengbojiang -v RET_ON_FAIL=1 \ 1340c6bd470Sfengbojiang -v MESSAGE='Using non https link to dpdk.org' \ 1350c6bd470Sfengbojiang -f $(dirname $(readlink -f $0))/check-forbidden-tokens.awk \ 1360c6bd470Sfengbojiang "$1" || res=1 1370c6bd470Sfengbojiang 1381646932aSjfb8856606 return $res 139d30ea906Sjfb8856606} 140d30ea906Sjfb8856606 1414418919fSjohnjiangcheck_experimental_tags() { # <patch> 1424418919fSjohnjiang res=0 1434418919fSjohnjiang 1444418919fSjohnjiang cat "$1" |awk ' 1454418919fSjohnjiang BEGIN { 1464418919fSjohnjiang current_file = ""; 1474418919fSjohnjiang ret = 0; 1484418919fSjohnjiang } 1494418919fSjohnjiang /^+++ b\// { 1504418919fSjohnjiang current_file = $2; 1514418919fSjohnjiang } 1524418919fSjohnjiang /^+.*__rte_experimental/ { 1534418919fSjohnjiang if (current_file ~ ".c$" ) { 1544418919fSjohnjiang print "Please only put __rte_experimental tags in " \ 1554418919fSjohnjiang "headers ("current_file")"; 1564418919fSjohnjiang ret = 1; 1574418919fSjohnjiang } 1584418919fSjohnjiang if ($1 != "+__rte_experimental" || $2 != "") { 1594418919fSjohnjiang print "__rte_experimental must appear alone on the line" \ 1604418919fSjohnjiang " immediately preceding the return type of a function." 1614418919fSjohnjiang ret = 1; 1624418919fSjohnjiang } 1634418919fSjohnjiang } 1644418919fSjohnjiang END { 1654418919fSjohnjiang exit ret; 1664418919fSjohnjiang }' || res=1 1674418919fSjohnjiang 1684418919fSjohnjiang return $res 1694418919fSjohnjiang} 1704418919fSjohnjiang 171*2d9fd380Sjfb8856606check_internal_tags() { # <patch> 172*2d9fd380Sjfb8856606 res=0 173*2d9fd380Sjfb8856606 174*2d9fd380Sjfb8856606 cat "$1" |awk ' 175*2d9fd380Sjfb8856606 BEGIN { 176*2d9fd380Sjfb8856606 current_file = ""; 177*2d9fd380Sjfb8856606 ret = 0; 178*2d9fd380Sjfb8856606 } 179*2d9fd380Sjfb8856606 /^+++ b\// { 180*2d9fd380Sjfb8856606 current_file = $2; 181*2d9fd380Sjfb8856606 } 182*2d9fd380Sjfb8856606 /^+.*__rte_internal/ { 183*2d9fd380Sjfb8856606 if (current_file ~ ".c$" ) { 184*2d9fd380Sjfb8856606 print "Please only put __rte_internal tags in " \ 185*2d9fd380Sjfb8856606 "headers ("current_file")"; 186*2d9fd380Sjfb8856606 ret = 1; 187*2d9fd380Sjfb8856606 } 188*2d9fd380Sjfb8856606 if ($1 != "+__rte_internal" || $2 != "") { 189*2d9fd380Sjfb8856606 print "__rte_internal must appear alone on the line" \ 190*2d9fd380Sjfb8856606 " immediately preceding the return type of" \ 191*2d9fd380Sjfb8856606 " a function." 192*2d9fd380Sjfb8856606 ret = 1; 193*2d9fd380Sjfb8856606 } 194*2d9fd380Sjfb8856606 } 195*2d9fd380Sjfb8856606 END { 196*2d9fd380Sjfb8856606 exit ret; 197*2d9fd380Sjfb8856606 }' || res=1 198*2d9fd380Sjfb8856606 199*2d9fd380Sjfb8856606 return $res 200*2d9fd380Sjfb8856606} 201*2d9fd380Sjfb8856606 2022bfe3f2eSlogwangnumber=0 203*2d9fd380Sjfb8856606range='origin/main..' 2042bfe3f2eSlogwangquiet=false 2052bfe3f2eSlogwangverbose=false 2064418919fSjohnjiangwhile getopts hn:qr:v ARG ; do 2072bfe3f2eSlogwang case $ARG in 2082bfe3f2eSlogwang n ) number=$OPTARG ;; 2092bfe3f2eSlogwang q ) quiet=true ;; 2104418919fSjohnjiang r ) range=$OPTARG ;; 2112bfe3f2eSlogwang v ) verbose=true ;; 2122bfe3f2eSlogwang h ) print_usage ; exit 0 ;; 2132bfe3f2eSlogwang ? ) print_usage ; exit 1 ;; 2142bfe3f2eSlogwang esac 2152bfe3f2eSlogwangdone 2162bfe3f2eSlogwangshift $(($OPTIND - 1)) 2172bfe3f2eSlogwang 218d30ea906Sjfb8856606if [ ! -f "$DPDK_CHECKPATCH_PATH" ] || [ ! -x "$DPDK_CHECKPATCH_PATH" ] ; then 2192bfe3f2eSlogwang print_usage >&2 2202bfe3f2eSlogwang echo 2212bfe3f2eSlogwang echo 'Cannot execute DPDK_CHECKPATCH_PATH' >&2 2222bfe3f2eSlogwang exit 1 2232bfe3f2eSlogwangfi 2242bfe3f2eSlogwang 225d30ea906Sjfb8856606print_headline() { # <title> 226d30ea906Sjfb8856606 printf '\n### %s\n\n' "$1" 227d30ea906Sjfb8856606 headline_printed=true 228d30ea906Sjfb8856606} 229d30ea906Sjfb8856606 2302bfe3f2eSlogwangtotal=0 2312bfe3f2eSlogwangstatus=0 2322bfe3f2eSlogwang 2332bfe3f2eSlogwangcheck () { # <patch> <commit> <title> 234d30ea906Sjfb8856606 local ret=0 235d30ea906Sjfb8856606 headline_printed=false 236d30ea906Sjfb8856606 2372bfe3f2eSlogwang total=$(($total + 1)) 238d30ea906Sjfb8856606 ! $verbose || print_headline "$3" 2392bfe3f2eSlogwang if [ -n "$1" ] ; then 240d30ea906Sjfb8856606 tmpinput=$1 2414418919fSjohnjiang else 242d30ea906Sjfb8856606 tmpinput=$(mktemp -t dpdk.checkpatches.XXXXXX) 2434418919fSjohnjiang trap "rm -f '$tmpinput'" INT 2444418919fSjohnjiang 2454418919fSjohnjiang if [ -n "$2" ] ; then 246d30ea906Sjfb8856606 git format-patch --find-renames \ 247d30ea906Sjfb8856606 --no-stat --stdout -1 $commit > "$tmpinput" 2482bfe3f2eSlogwang else 249d30ea906Sjfb8856606 cat > "$tmpinput" 2502bfe3f2eSlogwang fi 2514418919fSjohnjiang fi 252d30ea906Sjfb8856606 253d30ea906Sjfb8856606 ! $verbose || printf 'Running checkpatch.pl:\n' 254d30ea906Sjfb8856606 report=$($DPDK_CHECKPATCH_PATH $options "$tmpinput" 2>/dev/null) 255d30ea906Sjfb8856606 if [ $? -ne 0 ] ; then 256d30ea906Sjfb8856606 $headline_printed || print_headline "$3" 2572bfe3f2eSlogwang printf '%s\n' "$report" | sed -n '1,/^total:.*lines checked$/p' 258d30ea906Sjfb8856606 ret=1 259d30ea906Sjfb8856606 fi 260d30ea906Sjfb8856606 261d30ea906Sjfb8856606 ! $verbose || printf '\nChecking API additions/removals:\n' 262d30ea906Sjfb8856606 report=$($VALIDATE_NEW_API "$tmpinput") 263d30ea906Sjfb8856606 if [ $? -ne 0 ] ; then 264d30ea906Sjfb8856606 $headline_printed || print_headline "$3" 265d30ea906Sjfb8856606 printf '%s\n' "$report" 266d30ea906Sjfb8856606 ret=1 267d30ea906Sjfb8856606 fi 268d30ea906Sjfb8856606 269d30ea906Sjfb8856606 ! $verbose || printf '\nChecking forbidden tokens additions:\n' 270d30ea906Sjfb8856606 report=$(check_forbidden_additions "$tmpinput") 271d30ea906Sjfb8856606 if [ $? -ne 0 ] ; then 272d30ea906Sjfb8856606 $headline_printed || print_headline "$3" 273d30ea906Sjfb8856606 printf '%s\n' "$report" 274d30ea906Sjfb8856606 ret=1 275d30ea906Sjfb8856606 fi 276d30ea906Sjfb8856606 2774418919fSjohnjiang ! $verbose || printf '\nChecking __rte_experimental tags:\n' 2784418919fSjohnjiang report=$(check_experimental_tags "$tmpinput") 2794418919fSjohnjiang if [ $? -ne 0 ] ; then 2804418919fSjohnjiang $headline_printed || print_headline "$3" 2814418919fSjohnjiang printf '%s\n' "$report" 2824418919fSjohnjiang ret=1 2834418919fSjohnjiang fi 2844418919fSjohnjiang 285*2d9fd380Sjfb8856606 ! $verbose || printf '\nChecking __rte_internal tags:\n' 286*2d9fd380Sjfb8856606 report=$(check_internal_tags "$tmpinput") 287*2d9fd380Sjfb8856606 if [ $? -ne 0 ] ; then 288*2d9fd380Sjfb8856606 $headline_printed || print_headline "$3" 289*2d9fd380Sjfb8856606 printf '%s\n' "$report" 290*2d9fd380Sjfb8856606 ret=1 291*2d9fd380Sjfb8856606 fi 292*2d9fd380Sjfb8856606 2934418919fSjohnjiang if [ "$tmpinput" != "$1" ]; then 2944418919fSjohnjiang rm -f "$tmpinput" 2954418919fSjohnjiang trap - INT 2964418919fSjohnjiang fi 297d30ea906Sjfb8856606 [ $ret -eq 0 ] && return 0 298d30ea906Sjfb8856606 2992bfe3f2eSlogwang status=$(($status + 1)) 3002bfe3f2eSlogwang} 3012bfe3f2eSlogwang 3022bfe3f2eSlogwangif [ -n "$1" ] ; then 3032bfe3f2eSlogwang for patch in "$@" ; do 3042bfe3f2eSlogwang # Subject can be on 2 lines 3052bfe3f2eSlogwang subject=$(sed '/^Subject: */!d;s///;N;s,\n[[:space:]]\+, ,;s,\n.*,,;q' "$patch") 3062bfe3f2eSlogwang check "$patch" '' "$subject" 3072bfe3f2eSlogwang done 3082bfe3f2eSlogwangelif [ ! -t 0 ] ; then # stdin 3092bfe3f2eSlogwang subject=$(while read header value ; do 3102bfe3f2eSlogwang if [ "$header" = 'Subject:' ] ; then 3112bfe3f2eSlogwang IFS= read next 3122bfe3f2eSlogwang continuation=$(echo "$next" | sed -n 's,^[[:space:]]\+, ,p') 3132bfe3f2eSlogwang echo $value$continuation 3142bfe3f2eSlogwang break 3152bfe3f2eSlogwang fi 3162bfe3f2eSlogwang done) 3172bfe3f2eSlogwang check '' '' "$subject" 3182bfe3f2eSlogwangelse 3192bfe3f2eSlogwang if [ $number -eq 0 ] ; then 3204418919fSjohnjiang commits=$(git rev-list --reverse $range) 3212bfe3f2eSlogwang else 3222bfe3f2eSlogwang commits=$(git rev-list --reverse --max-count=$number HEAD) 3232bfe3f2eSlogwang fi 3242bfe3f2eSlogwang for commit in $commits ; do 3252bfe3f2eSlogwang subject=$(git log --format='%s' -1 $commit) 3262bfe3f2eSlogwang check '' $commit "$subject" 3272bfe3f2eSlogwang done 3282bfe3f2eSlogwangfi 3292bfe3f2eSlogwangpass=$(($total - $status)) 3302bfe3f2eSlogwang$quiet || printf '\n%d/%d valid patch' $pass $total 3312bfe3f2eSlogwang$quiet || [ $pass -le 1 ] || printf 'es' 3322bfe3f2eSlogwang$quiet || printf '\n' 3332bfe3f2eSlogwangexit $status 334