162306a36Sopenharmony_ci#!/usr/bin/gawk -f 262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci# Script to check sysctl documentation against source files 562306a36Sopenharmony_ci# 662306a36Sopenharmony_ci# Copyright (c) 2020 Stephen Kitt 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci# Example invocation: 962306a36Sopenharmony_ci# scripts/check-sysctl-docs -vtable="kernel" \ 1062306a36Sopenharmony_ci# Documentation/admin-guide/sysctl/kernel.rst \ 1162306a36Sopenharmony_ci# $(git grep -l register_sysctl_) 1262306a36Sopenharmony_ci# 1362306a36Sopenharmony_ci# Specify -vdebug=1 to see debugging information 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ciBEGIN { 1662306a36Sopenharmony_ci if (!table) { 1762306a36Sopenharmony_ci print "Please specify the table to look for using the table variable" > "/dev/stderr" 1862306a36Sopenharmony_ci exit 1 1962306a36Sopenharmony_ci } 2062306a36Sopenharmony_ci} 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci# The following globals are used: 2362306a36Sopenharmony_ci# children: maps ctl_table names and procnames to child ctl_table names 2462306a36Sopenharmony_ci# documented: maps documented entries (each key is an entry) 2562306a36Sopenharmony_ci# entries: maps ctl_table names and procnames to counts (so 2662306a36Sopenharmony_ci# enumerating the subkeys for a given ctl_table lists its 2762306a36Sopenharmony_ci# procnames) 2862306a36Sopenharmony_ci# files: maps procnames to source file names 2962306a36Sopenharmony_ci# paths: maps ctl_path names to paths 3062306a36Sopenharmony_ci# curpath: the name of the current ctl_path struct 3162306a36Sopenharmony_ci# curtable: the name of the current ctl_table struct 3262306a36Sopenharmony_ci# curentry: the name of the current proc entry (procname when parsing 3362306a36Sopenharmony_ci# a ctl_table, constructed path when parsing a ctl_path) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci# Remove punctuation from the given value 3762306a36Sopenharmony_cifunction trimpunct(value) { 3862306a36Sopenharmony_ci while (value ~ /^["&]/) { 3962306a36Sopenharmony_ci value = substr(value, 2) 4062306a36Sopenharmony_ci } 4162306a36Sopenharmony_ci while (value ~ /[]["&,}]$/) { 4262306a36Sopenharmony_ci value = substr(value, 1, length(value) - 1) 4362306a36Sopenharmony_ci } 4462306a36Sopenharmony_ci return value 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci# Print the information for the given entry 4862306a36Sopenharmony_cifunction printentry(entry) { 4962306a36Sopenharmony_ci seen[entry]++ 5062306a36Sopenharmony_ci printf "* %s from %s", entry, file[entry] 5162306a36Sopenharmony_ci if (documented[entry]) { 5262306a36Sopenharmony_ci printf " (documented)" 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci print "" 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci# Stage 1: build the list of documented entries 5962306a36Sopenharmony_ciFNR == NR && /^=+$/ { 6062306a36Sopenharmony_ci if (prevline ~ /Documentation for/) { 6162306a36Sopenharmony_ci # This is the main title 6262306a36Sopenharmony_ci next 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci # The previous line is a section title, parse it 6662306a36Sopenharmony_ci $0 = prevline 6762306a36Sopenharmony_ci if (debug) print "Parsing " $0 6862306a36Sopenharmony_ci inbrackets = 0 6962306a36Sopenharmony_ci for (i = 1; i <= NF; i++) { 7062306a36Sopenharmony_ci if (length($i) == 0) { 7162306a36Sopenharmony_ci continue 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci if (!inbrackets && substr($i, 1, 1) == "(") { 7462306a36Sopenharmony_ci inbrackets = 1 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci if (!inbrackets) { 7762306a36Sopenharmony_ci token = trimpunct($i) 7862306a36Sopenharmony_ci if (length(token) > 0 && token != "and") { 7962306a36Sopenharmony_ci if (debug) print trimpunct($i) 8062306a36Sopenharmony_ci documented[trimpunct($i)]++ 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci if (inbrackets && substr($i, length($i), 1) == ")") { 8462306a36Sopenharmony_ci inbrackets = 0 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ciFNR == NR { 9062306a36Sopenharmony_ci prevline = $0 9162306a36Sopenharmony_ci next 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci# Stage 2: process each file and find all sysctl tables 9662306a36Sopenharmony_ciBEGINFILE { 9762306a36Sopenharmony_ci delete children 9862306a36Sopenharmony_ci delete entries 9962306a36Sopenharmony_ci delete paths 10062306a36Sopenharmony_ci curpath = "" 10162306a36Sopenharmony_ci curtable = "" 10262306a36Sopenharmony_ci curentry = "" 10362306a36Sopenharmony_ci if (debug) print "Processing file " FILENAME 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/^static struct ctl_path/ { 10762306a36Sopenharmony_ci match($0, /static struct ctl_path ([^][]+)/, tables) 10862306a36Sopenharmony_ci curpath = tables[1] 10962306a36Sopenharmony_ci if (debug) print "Processing path " curpath 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/^static struct ctl_table/ { 11362306a36Sopenharmony_ci match($0, /static struct ctl_table ([^][]+)/, tables) 11462306a36Sopenharmony_ci curtable = tables[1] 11562306a36Sopenharmony_ci if (debug) print "Processing table " curtable 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/^};$/ { 11962306a36Sopenharmony_ci curpath = "" 12062306a36Sopenharmony_ci curtable = "" 12162306a36Sopenharmony_ci curentry = "" 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cicurpath && /\.procname[\t ]*=[\t ]*".+"/ { 12562306a36Sopenharmony_ci match($0, /.procname[\t ]*=[\t ]*"([^"]+)"/, names) 12662306a36Sopenharmony_ci if (curentry) { 12762306a36Sopenharmony_ci curentry = curentry "/" names[1] 12862306a36Sopenharmony_ci } else { 12962306a36Sopenharmony_ci curentry = names[1] 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci if (debug) print "Setting path " curpath " to " curentry 13262306a36Sopenharmony_ci paths[curpath] = curentry 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cicurtable && /\.procname[\t ]*=[\t ]*".+"/ { 13662306a36Sopenharmony_ci match($0, /.procname[\t ]*=[\t ]*"([^"]+)"/, names) 13762306a36Sopenharmony_ci curentry = names[1] 13862306a36Sopenharmony_ci if (debug) print "Adding entry " curentry " to table " curtable 13962306a36Sopenharmony_ci entries[curtable][curentry]++ 14062306a36Sopenharmony_ci file[curentry] = FILENAME 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/\.child[\t ]*=/ { 14462306a36Sopenharmony_ci child = trimpunct($NF) 14562306a36Sopenharmony_ci if (debug) print "Linking child " child " to table " curtable " entry " curentry 14662306a36Sopenharmony_ci children[curtable][curentry] = child 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ciEND { 15062306a36Sopenharmony_ci for (entry in documented) { 15162306a36Sopenharmony_ci if (!seen[entry]) { 15262306a36Sopenharmony_ci print "No implementation for " entry 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci} 156