2 # SPDX-License-Identifier: GPL-2.0
4 # Script to check sysctl documentation against source files
6 # Copyright (c) 2020 Stephen Kitt
9 # scripts/check-sysctl-docs -vtable="kernel" \
10 # Documentation/admin-guide/sysctl/kernel.rst \
11 # $(git grep -l register_sysctl_)
13 # Specify -vdebug=1 to see debugging information
17 print "Please specify the table to look for using the table variable" > "/dev/stderr"
22 # The following globals are used:
23 # children: maps ctl_table names and procnames to child ctl_table names
24 # documented: maps documented entries (each key is an entry)
25 # entries: maps ctl_table names and procnames to counts (so
26 # enumerating the subkeys for a given ctl_table lists its
28 # files: maps procnames to source file names
29 # paths: maps ctl_path names to paths
30 # curpath: the name of the current ctl_path struct
31 # curtable: the name of the current ctl_table struct
32 # curentry: the name of the current proc entry (procname when parsing
33 # a ctl_table, constructed path when parsing a ctl_path)
36 # Remove punctuation from the given value
37 function trimpunct
(value
) {
38 while (value ~
/^
["&]/) {
39 value = substr(value, 2)
41 while (value ~ /[]["&,}]$
/) {
42 value =
substr(value
, 1, length(value
) - 1)
47 # Print the information for the given entry
48 function printentry
(entry
) {
50 printf "* %s from %s", entry
, file
[entry
]
51 if (documented
[entry
]) {
52 printf " (documented)"
58 # Stage 1: build the list of documented entries
60 if (prevline ~
/Documentation
for/) {
61 # This is the main title
65 # The previous line is a section title, parse it
67 if (debug
) print "Parsing " $
0
69 for (i =
1; i
<=
NF; i
++) {
70 if (length($i
) ==
0) {
73 if (!inbrackets
&& substr($i
, 1, 1) ==
"(") {
78 if (length(token
) > 0 && token
!= "and") {
79 if (debug
) print trimpunct
($i
)
80 documented
[trimpunct
($i
)]++
83 if (inbrackets
&& substr($i
, length($i
), 1) ==
")") {
95 # Stage 2: process each file and find all sysctl tables
103 if (debug
) print "Processing file " FILENAME
106 /^static struct ctl_path
/ {
107 match($
0, /static struct ctl_path
([^
][]+)/, tables
)
109 if (debug
) print "Processing path " curpath
112 /^static struct ctl_table
/ {
113 match($
0, /static struct ctl_table
([^
][]+)/, tables
)
115 if (debug
) print "Processing table " curtable
124 curpath
&& /\.procname
[\t ]*=
[\t ]*".+"/ {
125 match($
0, /.procname
[\t ]*=
[\t ]*"([^"]+)"/, names)
127 curentry = curentry "/" names[1]
131 if (debug) print "Setting path
" curpath " to
" curentry
132 paths[curpath] = curentry
135 curtable && /\.procname[\t ]*=[\t ]*".
+"/ {
136 match($0, /.procname[\t ]*=[\t ]*"([^
"]+)"/, names
)
138 if (debug
) print "Adding entry " curentry
" to table " curtable
139 entries
[curtable
][curentry
]++
140 file
[curentry
] =
FILENAME
144 child = trimpunct
($
NF)
145 if (debug
) print "Linking child " child
" to table " curtable
" entry " curentry
146 children
[curtable
][curentry
] = child
149 /register_sysctl_table\
(.
*\
)/ {
150 match($
0, /register_sysctl_table\
(([^
)]+)\
)/, tables
)
151 if (debug
) print "Registering table " tables
[1]
152 if (children
[tables
[1]][table
]) {
153 for (entry in entries
[children
[tables
[1]][table
]]) {
159 /register_sysctl_paths\
(.
*\
)/ {
160 match($
0, /register_sysctl_paths\
(([^
)]+), ([^
)]+)\
)/, tables
)
161 if (debug
) print "Attaching table " tables
[2] " to path " tables
[1]
162 if (paths
[tables
[1]] == table
) {
163 for (entry in entries
[tables
[2]]) {
167 split(paths
[tables
[1]], components
, "/")
168 if (length(components
) > 1 && components
[1] == table
) {
169 # Count the first subdirectory as seen
170 seen
[components
[2]]++
176 for (entry in documented
) {
178 print "No implementation for " entry