xref: /linux/scripts/check-sysctl-docs (revision 4b290aae788e06561754b28c6842e4080957d3f7)
189b491bcSJoel Granados#!/usr/bin/env -S gawk -f
2021622dfSStephen Kitt# SPDX-License-Identifier: GPL-2.0
3021622dfSStephen Kitt
4021622dfSStephen Kitt# Script to check sysctl documentation against source files
5021622dfSStephen Kitt#
6021622dfSStephen Kitt# Copyright (c) 2020 Stephen Kitt
7021622dfSStephen Kitt
8021622dfSStephen Kitt# Example invocation:
9021622dfSStephen Kitt#	scripts/check-sysctl-docs -vtable="kernel" \
10021622dfSStephen Kitt#		Documentation/admin-guide/sysctl/kernel.rst \
110f6588b3SThomas Weißschuh#		$(git grep -l register_sysctl)
12021622dfSStephen Kitt#
13021622dfSStephen Kitt# Specify -vdebug=1 to see debugging information
14021622dfSStephen Kitt
15021622dfSStephen KittBEGIN {
16021622dfSStephen Kitt	if (!table) {
17021622dfSStephen Kitt	print "Please specify the table to look for using the table variable" > "/dev/stderr"
18021622dfSStephen Kitt	exit 1
19021622dfSStephen Kitt	}
20be0aef10SJoel Granados
21be0aef10SJoel Granados	# Documentation title skiplist
22be0aef10SJoel Granados	skiplist[0] = "^Documentation for"
23be0aef10SJoel Granados	skiplist[1] = "Network core options$"
24be0aef10SJoel Granados	skiplist[2] = "POSIX message queues filesystem$"
25be0aef10SJoel Granados	skiplist[3] = "Configuration options"
26be0aef10SJoel Granados	skiplist[4] = ". /proc/sys/fs"
27be0aef10SJoel Granados	skiplist[5] = "^Introduction$"
28be0aef10SJoel Granados	skiplist[6] = "^seccomp$"
29be0aef10SJoel Granados	skiplist[7] = "^pty$"
30be0aef10SJoel Granados	skiplist[8] = "^firmware_config$"
31be0aef10SJoel Granados	skiplist[9] = "^random$"
32021622dfSStephen Kitt}
33021622dfSStephen Kitt
34021622dfSStephen Kitt# The following globals are used:
35021622dfSStephen Kitt# documented: maps documented entries (each key is an entry)
36021622dfSStephen Kitt# entries: maps ctl_table names and procnames to counts (so
37021622dfSStephen Kitt#          enumerating the subkeys for a given ctl_table lists its
38021622dfSStephen Kitt#          procnames)
39021622dfSStephen Kitt# curtable: the name of the current ctl_table struct
40021622dfSStephen Kitt# curentry: the name of the current proc entry (procname when parsing
41021622dfSStephen Kitt#           a ctl_table, constructed path when parsing a ctl_path)
42021622dfSStephen Kitt
43021622dfSStephen Kitt
44021622dfSStephen Kitt# Remove punctuation from the given value
45021622dfSStephen Kittfunction trimpunct(value) {
46021622dfSStephen Kitt	while (value ~ /^["&]/) {
47021622dfSStephen Kitt		value = substr(value, 2)
48021622dfSStephen Kitt	}
49021622dfSStephen Kitt	while (value ~ /[]["&,}]$/) {
50021622dfSStephen Kitt		value = substr(value, 1, length(value) - 1)
51021622dfSStephen Kitt	}
52021622dfSStephen Kitt	return value
53021622dfSStephen Kitt}
54021622dfSStephen Kitt
55021622dfSStephen Kitt# Print the information for the given entry
56021622dfSStephen Kittfunction printentry(entry) {
57021622dfSStephen Kitt	seen[entry]++
58021622dfSStephen Kitt	printf "* %s from %s", entry, file[entry]
59021622dfSStephen Kitt	if (documented[entry]) {
60021622dfSStephen Kitt		printf " (documented)"
61021622dfSStephen Kitt	}
62021622dfSStephen Kitt	print ""
63021622dfSStephen Kitt}
64021622dfSStephen Kitt
65021622dfSStephen Kitt
66021622dfSStephen Kitt# Stage 1: build the list of documented entries
67021622dfSStephen KittFNR == NR && /^=+$/ {
68be0aef10SJoel Granados	for (i in skiplist) {
69be0aef10SJoel Granados		if (prevline ~ skiplist[i]) {
70021622dfSStephen Kitt			next
71021622dfSStephen Kitt		}
72be0aef10SJoel Granados	}
73021622dfSStephen Kitt
74021622dfSStephen Kitt	# The previous line is a section title, parse it
75021622dfSStephen Kitt	$0 = prevline
76021622dfSStephen Kitt	if (debug) print "Parsing " $0
77021622dfSStephen Kitt	inbrackets = 0
78021622dfSStephen Kitt	for (i = 1; i <= NF; i++) {
79021622dfSStephen Kitt		if (length($i) == 0) {
80021622dfSStephen Kitt			continue
81021622dfSStephen Kitt		}
82021622dfSStephen Kitt		if (!inbrackets && substr($i, 1, 1) == "(") {
83021622dfSStephen Kitt			inbrackets = 1
84021622dfSStephen Kitt		}
85021622dfSStephen Kitt		if (!inbrackets) {
86021622dfSStephen Kitt			token = trimpunct($i)
87021622dfSStephen Kitt			if (length(token) > 0 && token != "and") {
88021622dfSStephen Kitt				if (debug) print trimpunct($i)
89021622dfSStephen Kitt					documented[trimpunct($i)]++
90021622dfSStephen Kitt			}
91021622dfSStephen Kitt		}
92021622dfSStephen Kitt		if (inbrackets && substr($i, length($i), 1) == ")") {
93021622dfSStephen Kitt			inbrackets = 0
94021622dfSStephen Kitt		}
95021622dfSStephen Kitt	}
96021622dfSStephen Kitt}
97021622dfSStephen Kitt
98021622dfSStephen KittFNR == NR {
99021622dfSStephen Kitt	prevline = $0
100021622dfSStephen Kitt	next
101021622dfSStephen Kitt}
102021622dfSStephen Kitt
103021622dfSStephen Kitt
104021622dfSStephen Kitt# Stage 2: process each file and find all sysctl tables
105021622dfSStephen KittBEGINFILE {
106021622dfSStephen Kitt	delete entries
107021622dfSStephen Kitt	curtable = ""
108021622dfSStephen Kitt	curentry = ""
1094f1136a5SThomas Weißschuh	delete vars
110021622dfSStephen Kitt	if (debug) print "Processing file " FILENAME
111021622dfSStephen Kitt}
112021622dfSStephen Kitt
1130f6588b3SThomas Weißschuh/^static( const)? struct ctl_table/ {
1140f6588b3SThomas Weißschuh	match($0, /static( const)? struct ctl_table ([^][]+)/, tables)
1150f6588b3SThomas Weißschuh	curtable = tables[2]
116021622dfSStephen Kitt	if (debug) print "Processing table " curtable
117021622dfSStephen Kitt}
118021622dfSStephen Kitt
119021622dfSStephen Kitt/^};$/ {
120021622dfSStephen Kitt	curtable = ""
121021622dfSStephen Kitt	curentry = ""
1224f1136a5SThomas Weißschuh	delete vars
123021622dfSStephen Kitt}
124021622dfSStephen Kitt
125021622dfSStephen Kittcurtable && /\.procname[\t ]*=[\t ]*".+"/ {
126021622dfSStephen Kitt	match($0, /.procname[\t ]*=[\t ]*"([^"]+)"/, names)
127021622dfSStephen Kitt	curentry = names[1]
128021622dfSStephen Kitt	if (debug) print "Adding entry " curentry " to table " curtable
129021622dfSStephen Kitt	entries[curtable][curentry]++
130021622dfSStephen Kitt	file[curentry] = FILENAME
131021622dfSStephen Kitt}
132021622dfSStephen Kitt
133e97a96baSJoel Granadoscurtable && /UCOUNT_ENTRY.*/ {
134e97a96baSJoel Granados	match($0, /UCOUNT_ENTRY\("([^"]+)"\)/, names)
135e97a96baSJoel Granados	curentry = names[1]
136e97a96baSJoel Granados	if (debug) print "Adding entry " curentry " to table " curtable
137e97a96baSJoel Granados	entries[curtable][curentry]++
138e97a96baSJoel Granados	file[curentry] = FILENAME
139e97a96baSJoel Granados}
140e97a96baSJoel Granados
1410f6588b3SThomas Weißschuh/register_sysctl.*/ {
1420f6588b3SThomas Weißschuh	match($0, /register_sysctl(|_init|_sz)\("([^"]+)" *, *([^,)]+)/, tables)
1430f6588b3SThomas Weißschuh	if (debug) print "Registering table " tables[3] " at " tables[2]
1440f6588b3SThomas Weißschuh	if (tables[2] == table) {
1450f6588b3SThomas Weißschuh		for (entry in entries[tables[3]]) {
1460f6588b3SThomas Weißschuh			printentry(entry)
1470f6588b3SThomas Weißschuh		}
1480f6588b3SThomas Weißschuh	}
149021622dfSStephen Kitt}
150021622dfSStephen Kitt
1514f1136a5SThomas Weißschuh/kmemdup.*/ {
1524f1136a5SThomas Weißschuh	match($0, /([^ \t]+) *= *kmemdup\(([^,]+) *,/, names)
1534f1136a5SThomas Weißschuh	if (debug) print "Found variable " names[1] " for table " names[2]
1544f1136a5SThomas Weißschuh	if (names[2] in entries) {
1554f1136a5SThomas Weißschuh		vars[names[1]] = names[2]
1564f1136a5SThomas Weißschuh	}
1574f1136a5SThomas Weißschuh}
1584f1136a5SThomas Weißschuh
1594f1136a5SThomas Weißschuh/__register_sysctl_table.*/ {
1604f1136a5SThomas Weißschuh	match($0, /__register_sysctl_table\([^,]+, *"([^"]+)" *, *([^,]+)/, tables)
1614f1136a5SThomas Weißschuh	if (debug) print "Registering variable table " tables[2] " at " tables[1]
1624f1136a5SThomas Weißschuh	if (tables[1] == table && tables[2] in vars) {
1634f1136a5SThomas Weißschuh		for (entry in entries[vars[tables[2]]]) {
1644f1136a5SThomas Weißschuh			printentry(entry)
1654f1136a5SThomas Weißschuh		}
1664f1136a5SThomas Weißschuh	}
1674f1136a5SThomas Weißschuh}
1684f1136a5SThomas Weißschuh
169021622dfSStephen KittEND {
170021622dfSStephen Kitt	for (entry in documented) {
171*999aab7fSJoel Granados		if (!seen[entry])
172021622dfSStephen Kitt			print "No implementation for " entry
173021622dfSStephen Kitt	}
174021622dfSStephen Kitt}
175