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