]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
tools: verify the consistency of manpages for all programs
authorChristian Goeschel Ndjomouo <cgoesc2@wgu.edu>
Wed, 31 Dec 2025 23:56:22 +0000 (18:56 -0500)
committerKarel Zak <kzak@redhat.com>
Wed, 7 Jan 2026 09:42:22 +0000 (10:42 +0100)
The tools/checkmanpage.sh script ensures that all programs
have a corresponding manpage as well as the integrity of
all described long options in the manpage based on the
respective programs source code.

Signed-off-by: Christian Goeschel Ndjomouo <cgoesc2@wgu.edu>
Makefile.am
tools/checkmanpage.sh [new file with mode: 0755]

index 75bab88f4e055230e4dd631b2e6d8f8fd0a912f2..7c07b63a5cad81a2f5884216ecfb79c9ffebf08a 100644 (file)
@@ -338,6 +338,9 @@ checkdecl:
 checkcompletion:
        @ $(top_srcdir)/tools/checkcompletion.sh $(top_srcdir)
 
+checkmanpage:
+       @ $(top_srcdir)/tools/checkmanpage.sh $(top_srcdir)
+
 checkusage:
        @ $(top_srcdir)/tools/checkusage.sh $(top_srcdir) \
                $(bin_PROGRAMS) $(sbin_PROGRAMS) \
diff --git a/tools/checkmanpage.sh b/tools/checkmanpage.sh
new file mode 100755 (executable)
index 0000000..948e7ff
--- /dev/null
@@ -0,0 +1,142 @@
+#!/bin/bash
+
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# Copyright (C) 2025 Christian Goeschel Ndjomouo <cgoesc2@wgu.edu>
+#
+# This script verifies if each program has a corresponding manpage
+# and checks if said manpages have a description for each program's
+# long options. The list of program long options is based on the
+# respective program's source code. 
+
+top_srcdir="${1:-.}"
+if [ -d "${top_srcdir}" ]; then
+        shift 1
+else
+        echo "directory '${top_srcdir}' not found" >&2
+        exit 1
+fi
+
+# These are programs that we do not need to check on
+# swapoff: merged into the swapon manpage
+ignore_programs="swapoff"
+
+# We only need manpages for sections 1,7 and 8
+manpages="$( find "$top_srcdir" -name "*[178].adoc" -type f | uniq )"
+
+# Extract all user-facing programs from Makemodule.am files
+# We look for: bin_PROGRAMS, sbin_PROGRAMS, usrbin_exec_PROGRAMS, usrsbin_exec_PROGRAMS
+function extract_programs() {
+        find "$top_srcdir" -name "Makemodule.am" -type f -exec grep -h \
+                -E "^(bin|sbin|usrbin_exec|usrsbin_exec)_PROGRAMS \+=" {} \; \
+                | sed 's/.*+= *//' \
+                | tr ' ' '\n' \
+                | sed 's/\\//' \
+                | grep -v '^$' \
+                | grep -v '\.static$' \
+                | sort -u
+}
+
+function find_prog_manpage() {
+        local prog
+        prog="$1"
+
+        for m in ${manpages}; do
+                if [[ "${m##*/}" =~ ^"${prog}"\.[1-9]\.adoc$ ]]; then
+                        echo "${m}"
+                        break
+                fi
+        done
+}
+
+function get_manpage_options() {
+        local adoc
+        adoc="$1"
+
+        opts="$(cat "$adoc" \
+                        | grep -o -P '[[:space:]]*--(?![^[:alnum:]])[A-Za-z-.0-9_]*' \
+                        | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' \
+                        | sort \
+                        | uniq )"
+
+        # --help and --version are included with a manpage stub @ man-common/help-version.adoc
+        if grep -E 'include::man-common\/help-version.adoc\[\]' "$adoc" &>/dev/null; then
+                opts="$(printf -- "--version\n--help\n%s" "$opts" | sort | uniq )"
+        fi
+
+        # --annotate is included with a manpage stub @ man-common/annotate.adoc
+        if grep -E 'include::man-common\/annotate.adoc\[\]' "$adoc" &>/dev/null; then
+                opts="$(printf -- "--annotate\n%s" "$opts" | sort | uniq )"
+        fi
+
+        # --hyperlink is included with a manpage stub @ man-common/hyperlink.adoc
+        if grep -E 'include::man-common\/hyperlink.adoc\[\]' "$adoc" &>/dev/null; then
+                opts="$(printf -- "--hyperlink\n%s" "$opts" | sort | uniq )"
+        fi
+
+        echo "$opts"
+}
+
+function check_manpage_integrity() {
+        local prog
+        prog="$1"
+
+        adoc="$(find_prog_manpage "$prog")"
+        if [ -z "$adoc" ]; then
+                echo "ERROR: no manpage found for $prog" >&2
+                return 1
+        fi
+
+        manpage_opts="$( get_manpage_options "$adoc" )"
+
+        prog_long_opts="$( TOP_SRCDIR="${top_srcdir}" "${top_srcdir}"/tools/get-options.sh "$prog" \
+                        | sed -e 's/^$//' -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
+
+        if [[ "$?" != "0" || -z "$prog_long_opts" ]]; then
+                echo "Failed to get long options for $prog"
+                return 1
+        fi
+
+        # tools/get-options.sh prints 'ENOTSUP' when it receives the name of an
+        # unsupported program. See comments for the 'unsupported_programs' variable
+        # in tools/get-options.sh for more details.
+        #
+        # We do not treat this case as an error, thereby we simply return 0 to the
+        # caller and skip the comparison.
+        if [ "$prog_long_opts" == "ENOTSUP" ]; then
+                return 0
+        fi
+
+        res="$( comm -23 <(echo "${prog_long_opts}") <(echo "${manpage_opts}") )"
+        if [ -n "$res" ]; then
+                printf "%s\n%s\n" "${prog} (missing/extraneous manpage description(s)):" "$res"
+                return 1
+        fi
+
+        return 0
+}
+
+function main() {
+        programs="$(extract_programs)"
+
+        errors=0
+
+        for p in $programs; do
+                [[ "$p" =~ $ignore_programs ]] && continue
+                check_manpage_integrity "$p" || errors=$((errors + 1))
+        done
+
+        exit $errors
+}
+
+main