Commit | Line | Data |
---|---|---|
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 \ | |
11 | # $(git grep -l register_sysctl_) | |
12 | # | |
13 | # Specify -vdebug=1 to see debugging information | |
14 | ||
15 | BEGIN { | |
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: | |
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 | |
27 | # procnames) | |
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) | |
34 | ||
35 | ||
36 | # Remove punctuation from the given value | |
37 | function trimpunct(value) { | |
38 | while (value ~ /^["&]/) { | |
39 | value = substr(value, 2) | |
40 | } | |
41 | while (value ~ /[]["&,}]$/) { | |
42 | value = substr(value, 1, length(value) - 1) | |
43 | } | |
44 | return value | |
45 | } | |
46 | ||
47 | # Print the information for the given entry | |
48 | function printentry(entry) { | |
49 | seen[entry]++ | |
50 | printf "* %s from %s", entry, file[entry] | |
51 | if (documented[entry]) { | |
52 | printf " (documented)" | |
53 | } | |
54 | print "" | |
55 | } | |
56 | ||
57 | ||
58 | # Stage 1: build the list of documented entries | |
59 | FNR == NR && /^=+$/ { | |
60 | if (prevline ~ /Documentation for/) { | |
61 | # This is the main title | |
62 | next | |
63 | } | |
64 | ||
65 | # The previous line is a section title, parse it | |
66 | $0 = prevline | |
67 | if (debug) print "Parsing " $0 | |
68 | inbrackets = 0 | |
69 | for (i = 1; i <= NF; i++) { | |
70 | if (length($i) == 0) { | |
71 | continue | |
72 | } | |
73 | if (!inbrackets && substr($i, 1, 1) == "(") { | |
74 | inbrackets = 1 | |
75 | } | |
76 | if (!inbrackets) { | |
77 | token = trimpunct($i) | |
78 | if (length(token) > 0 && token != "and") { | |
79 | if (debug) print trimpunct($i) | |
80 | documented[trimpunct($i)]++ | |
81 | } | |
82 | } | |
83 | if (inbrackets && substr($i, length($i), 1) == ")") { | |
84 | inbrackets = 0 | |
85 | } | |
86 | } | |
87 | } | |
88 | ||
89 | FNR == NR { | |
90 | prevline = $0 | |
91 | next | |
92 | } | |
93 | ||
94 | ||
95 | # Stage 2: process each file and find all sysctl tables | |
96 | BEGINFILE { | |
97 | delete children | |
98 | delete entries | |
99 | delete paths | |
100 | curpath = "" | |
101 | curtable = "" | |
102 | curentry = "" | |
103 | if (debug) print "Processing file " FILENAME | |
104 | } | |
105 | ||
106 | /^static struct ctl_path/ { | |
107 | match($0, /static struct ctl_path ([^][]+)/, tables) | |
108 | curpath = tables[1] | |
109 | if (debug) print "Processing path " curpath | |
110 | } | |
111 | ||
112 | /^static struct ctl_table/ { | |
113 | match($0, /static struct ctl_table ([^][]+)/, tables) | |
114 | curtable = tables[1] | |
115 | if (debug) print "Processing table " curtable | |
116 | } | |
117 | ||
118 | /^};$/ { | |
119 | curpath = "" | |
120 | curtable = "" | |
121 | curentry = "" | |
122 | } | |
123 | ||
124 | curpath && /\.procname[\t ]*=[\t ]*".+"/ { | |
125 | match($0, /.procname[\t ]*=[\t ]*"([^"]+)"/, names) | |
126 | if (curentry) { | |
127 | curentry = curentry "/" names[1] | |
128 | } else { | |
129 | curentry = names[1] | |
130 | } | |
131 | if (debug) print "Setting path " curpath " to " curentry | |
132 | paths[curpath] = curentry | |
133 | } | |
134 | ||
135 | curtable && /\.procname[\t ]*=[\t ]*".+"/ { | |
136 | match($0, /.procname[\t ]*=[\t ]*"([^"]+)"/, names) | |
137 | curentry = names[1] | |
138 | if (debug) print "Adding entry " curentry " to table " curtable | |
139 | entries[curtable][curentry]++ | |
140 | file[curentry] = FILENAME | |
141 | } | |
142 | ||
143 | /\.child[\t ]*=/ { | |
144 | child = trimpunct($NF) | |
145 | if (debug) print "Linking child " child " to table " curtable " entry " curentry | |
146 | children[curtable][curentry] = child | |
147 | } | |
148 | ||
021622df SK |
149 | END { |
150 | for (entry in documented) { | |
151 | if (!seen[entry]) { | |
152 | print "No implementation for " entry | |
153 | } | |
154 | } | |
155 | } |