Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
[linux-2.6-block.git] / scripts / check-sysctl-docs
CommitLineData
021622df
SK
1#!/usr/bin/gawk -f
2# SPDX-License-Identifier: GPL-2.0
3
4# Script to check sysctl documentation against source files
5#
6# Copyright (c) 2020 Stephen Kitt
7
8# Example invocation:
9# scripts/check-sysctl-docs -vtable="kernel" \
10# Documentation/admin-guide/sysctl/kernel.rst \
0f6588b3 11# $(git grep -l register_sysctl)
021622df
SK
12#
13# Specify -vdebug=1 to see debugging information
14
15BEGIN {
16 if (!table) {
17 print "Please specify the table to look for using the table variable" > "/dev/stderr"
18 exit 1
19 }
20}
21
22# The following globals are used:
021622df
SK
23# documented: maps documented entries (each key is an entry)
24# entries: maps ctl_table names and procnames to counts (so
25# enumerating the subkeys for a given ctl_table lists its
26# procnames)
021622df
SK
27# curtable: the name of the current ctl_table struct
28# curentry: the name of the current proc entry (procname when parsing
29# a ctl_table, constructed path when parsing a ctl_path)
30
31
32# Remove punctuation from the given value
33function trimpunct(value) {
34 while (value ~ /^["&]/) {
35 value = substr(value, 2)
36 }
37 while (value ~ /[]["&,}]$/) {
38 value = substr(value, 1, length(value) - 1)
39 }
40 return value
41}
42
43# Print the information for the given entry
44function printentry(entry) {
45 seen[entry]++
46 printf "* %s from %s", entry, file[entry]
47 if (documented[entry]) {
48 printf " (documented)"
49 }
50 print ""
51}
52
53
54# Stage 1: build the list of documented entries
55FNR == NR && /^=+$/ {
56 if (prevline ~ /Documentation for/) {
57 # This is the main title
58 next
59 }
60
61 # The previous line is a section title, parse it
62 $0 = prevline
63 if (debug) print "Parsing " $0
64 inbrackets = 0
65 for (i = 1; i <= NF; i++) {
66 if (length($i) == 0) {
67 continue
68 }
69 if (!inbrackets && substr($i, 1, 1) == "(") {
70 inbrackets = 1
71 }
72 if (!inbrackets) {
73 token = trimpunct($i)
74 if (length(token) > 0 && token != "and") {
75 if (debug) print trimpunct($i)
76 documented[trimpunct($i)]++
77 }
78 }
79 if (inbrackets && substr($i, length($i), 1) == ")") {
80 inbrackets = 0
81 }
82 }
83}
84
85FNR == NR {
86 prevline = $0
87 next
88}
89
90
91# Stage 2: process each file and find all sysctl tables
92BEGINFILE {
021622df 93 delete entries
021622df
SK
94 curtable = ""
95 curentry = ""
4f1136a5 96 delete vars
021622df
SK
97 if (debug) print "Processing file " FILENAME
98}
99
0f6588b3
TW
100/^static( const)? struct ctl_table/ {
101 match($0, /static( const)? struct ctl_table ([^][]+)/, tables)
102 curtable = tables[2]
021622df
SK
103 if (debug) print "Processing table " curtable
104}
105
106/^};$/ {
021622df
SK
107 curtable = ""
108 curentry = ""
4f1136a5 109 delete vars
021622df
SK
110}
111
021622df
SK
112curtable && /\.procname[\t ]*=[\t ]*".+"/ {
113 match($0, /.procname[\t ]*=[\t ]*"([^"]+)"/, names)
114 curentry = names[1]
115 if (debug) print "Adding entry " curentry " to table " curtable
116 entries[curtable][curentry]++
117 file[curentry] = FILENAME
118}
119
0f6588b3
TW
120/register_sysctl.*/ {
121 match($0, /register_sysctl(|_init|_sz)\("([^"]+)" *, *([^,)]+)/, tables)
122 if (debug) print "Registering table " tables[3] " at " tables[2]
123 if (tables[2] == table) {
124 for (entry in entries[tables[3]]) {
125 printentry(entry)
126 }
127 }
021622df
SK
128}
129
4f1136a5
TW
130/kmemdup.*/ {
131 match($0, /([^ \t]+) *= *kmemdup\(([^,]+) *,/, names)
132 if (debug) print "Found variable " names[1] " for table " names[2]
133 if (names[2] in entries) {
134 vars[names[1]] = names[2]
135 }
136}
137
138/__register_sysctl_table.*/ {
139 match($0, /__register_sysctl_table\([^,]+, *"([^"]+)" *, *([^,]+)/, tables)
140 if (debug) print "Registering variable table " tables[2] " at " tables[1]
141 if (tables[1] == table && tables[2] in vars) {
142 for (entry in entries[vars[tables[2]]]) {
143 printentry(entry)
144 }
145 }
146}
147
021622df
SK
148END {
149 for (entry in documented) {
150 if (!seen[entry]) {
151 print "No implementation for " entry
152 }
153 }
154}