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 # 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
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)
32 # Remove punctuation from the given value
33 function trimpunct(value) {
34 while (value ~ /^["&]/) {
35 value = substr(value, 2)
37 while (value ~ /[]["&,}]$/) {
38 value = substr(value, 1, length(value) - 1)
43 # Print the information for the given entry
44 function printentry(entry) {
46 printf "* %s from %s", entry, file[entry]
47 if (documented[entry]) {
48 printf " (documented)"
54 # Stage 1: build the list of documented entries
56 if (prevline ~ /Documentation for/) {
57 # This is the main title
61 # The previous line is a section title, parse it
63 if (debug) print "Parsing " $0
65 for (i = 1; i <= NF; i++) {
66 if (length($i) == 0) {
69 if (!inbrackets && substr($i, 1, 1) == "(") {
74 if (length(token) > 0 && token != "and") {
75 if (debug) print trimpunct($i)
76 documented[trimpunct($i)]++
79 if (inbrackets && substr($i, length($i), 1) == ")") {
91 # Stage 2: process each file and find all sysctl tables
97 if (debug) print "Processing file " FILENAME
100 /^static( const)? struct ctl_table/ {
101 match($0, /static( const)? struct ctl_table ([^][]+)/, tables)
103 if (debug) print "Processing table " curtable
112 curtable && /\.procname[\t ]*=[\t ]*".+"/ {
113 match($0, /.procname[\t ]*=[\t ]*"([^"]+)"/, names)
115 if (debug) print "Adding entry " curentry " to table " curtable
116 entries[curtable][curentry]++
117 file[curentry] = FILENAME
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]]) {
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]
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]]]) {
149 for (entry in documented) {
151 print "No implementation for " entry