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