xref: /aosp_15_r20/external/ltp/doc/conf.py (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1# Configuration file for the Sphinx documentation builder.
2#
3# For the full list of built-in configuration values, see the documentation:
4# https://www.sphinx-doc.org/en/master/usage/configuration.html
5
6import os
7import re
8import sphinx
9import socket
10import urllib.request
11
12# -- Project information -----------------------------------------------------
13# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
14
15project = 'Linux Test Project'
16copyright = '2024, Linux Test Project'
17author = 'Linux Test Project'
18release = '1.0'
19
20# -- General configuration ---------------------------------------------------
21# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
22
23extensions = [
24    'linuxdoc.rstKernelDoc',
25    'sphinxcontrib.spelling',
26    'sphinx.ext.extlinks'
27]
28
29exclude_patterns = ["html*", '_static*']
30extlinks = {
31    'repo': ('https://github.com/linux-test-project/ltp/%s', '%s'),
32    'master': ('https://github.com/linux-test-project/ltp/blob/master/%s', '%s'),
33    'git_man': ('https://git-scm.com/docs/git-%s', 'git %s'),
34    # TODO: allow 2nd parameter to show page description instead of plain URL
35    'kernel_doc': ('https://docs.kernel.org/%s.html', 'https://docs.kernel.org/%s.html'),
36    'kernel_tree': ('https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/%s', '%s'),
37}
38
39spelling_lang = "en_US"
40spelling_warning = True
41spelling_exclude_patterns=['users/stats.rst']
42spelling_word_list_filename = "spelling_wordlist"
43
44# -- Options for HTML output -------------------------------------------------
45# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
46
47html_theme = 'sphinx_rtd_theme'
48html_static_path = ['_static']
49
50
51def generate_syscalls_stats(_):
52    """
53    Generate statistics for syscalls. We fetch the syscalls list from the kernel
54    sources, then we compare it with testcases/kernel/syscalls folder and
55    generate a file that is included in the statistics documentation section.
56    """
57    output = '_static/syscalls.rst'
58
59    # sometimes checking testcases/kernel/syscalls file names are not enough,
60    # because in some cases (i.e. io_ring) syscalls are tested, but they are
61    # part of a more complex scenario. In the following list, we define syscalls
62    # which we know they are 100% tested already.
63    white_list = [
64        'rt_sigpending',
65        'sethostname',
66        'lsetxattr',
67        'inotify_add_watch',
68        'inotify_rm_watch',
69        'newfstatat',
70        'pselect6',
71        'fanotify_init',
72        'fanotify_mark',
73        'prlimit64',
74        'getdents64',
75        'pkey_mprotect',
76        'pkey_alloc',
77        'pkey_free',
78        'io_uring_setup',
79        'io_uring_enter',
80        'io_uring_register',
81        'epoll_pwait2',
82        'quotactl_fd',
83        'pread64',
84        'pwrite64',
85        'fadvise64',
86        'getmsg',
87        'getpmsg',
88        'putmsg',
89        'putpmsg',
90    ]
91
92    # populate with not implemented, reserved, unmaintained syscalls defined
93    # inside the syscalls file
94    black_list = [
95        'reserved177',
96        'reserved193',
97        'rseq',
98        '_newselect',
99        '_sysctl',
100        'create_module',
101        'get_kernel_syms',
102        'query_module',
103        'nfsservctl',
104        'afs_syscall',
105        'sysmips',
106        'mq_getsetattr',
107        'vserver',
108    ]
109
110    # fetch syscalls file
111    error = False
112    try:
113        socket.setdefaulttimeout(3)
114        urllib.request.urlretrieve(
115            "https://raw.githubusercontent.com/torvalds/linux/master/arch/mips/kernel/syscalls/syscall_n64.tbl",
116            "syscalls.tbl")
117    except Exception as err:
118        error = True
119        logger = sphinx.util.logging.getLogger(__name__)
120        msg = "Can't download syscall_n64.tbl from kernel sources"
121        logger.warning(msg)
122
123        with open(output, 'w+') as stats:
124            stats.write(f".. warning::\n\n    {msg}")
125
126    if error:
127        return
128
129    text = [
130        'Syscalls\n',
131        '--------\n\n',
132    ]
133
134    # collect all available kernel syscalls
135    regexp = re.compile(r'\d+\s+n64\s+(?P<syscall>\w+)\s+\w+')
136    ker_syscalls = []
137    with open("syscalls.tbl", 'r') as data:
138        for line in data:
139            match = regexp.search(line)
140            if match:
141                ker_syscalls.append(match.group('syscall'))
142
143    # collect all LTP tested syscalls
144    ltp_syscalls = []
145    for root, _, files in os.walk('../testcases/kernel/syscalls'):
146        for myfile in files:
147            if myfile.endswith('.c'):
148                ltp_syscalls.append(myfile)
149
150    # compare kernel syscalls with LTP tested syscalls
151    syscalls = {}
152    for kersc in ker_syscalls:
153        if kersc in black_list:
154            continue
155
156        if kersc not in syscalls:
157            if kersc in white_list:
158                syscalls[kersc] = True
159                continue
160
161            syscalls[kersc] = False
162
163        for ltpsc in ltp_syscalls:
164            if ltpsc.startswith(kersc):
165                syscalls[kersc] = True
166
167    # generate the statistics file
168    tested_syscalls = [key for key, val in syscalls.items() if val]
169    text.append('syscalls which are tested under :master:`testcases/kernel/syscalls`:\n\n')
170    text.append(f'* kernel syscalls: {len(ker_syscalls)}\n')
171    text.append(f'* tested syscalls: {len(tested_syscalls)}\n\n')
172
173    # create tested/untested syscalls table
174    index_tested = 0
175    table_tested = [
176        'Tested syscalls\n',
177        '~~~~~~~~~~~~~~~\n\n',
178        '.. list-table::\n',
179        '    :header-rows: 0\n\n',
180    ]
181
182    index_untest = 0
183    table_untest = [
184        'Untested syscalls\n',
185        '~~~~~~~~~~~~~~~~~\n\n',
186        '.. list-table::\n',
187        '    :header-rows: 0\n\n',
188    ]
189
190    for sysname, tested in syscalls.items():
191        if tested:
192            if (index_tested % 3) == 0:
193                table_tested.append(f'    * - {sysname}\n')
194            else:
195                table_tested.append(f'      - {sysname}\n')
196
197            index_tested += 1
198        else:
199            if (index_untest % 3) == 0:
200                table_untest.append(f'    * - {sysname}\n')
201            else:
202                table_untest.append(f'      - {sysname}\n')
203
204            index_untest += 1
205
206    left = index_tested % 3
207    if left > 0:
208        for index in range(0, 3 - left):
209            table_tested.append(f'      -\n')
210
211    left = index_untest % 3
212    if left > 0:
213        for index in range(0, 3 - left):
214            table_untest.append(f'      -\n')
215
216    text.extend(table_tested)
217    text.append('\n')
218    text.extend(table_untest)
219
220    # write the file
221    with open(output, 'w+') as stats:
222        stats.writelines(text)
223
224
225def setup(app):
226    app.add_css_file('custom.css')
227    app.connect('builder-inited', generate_syscalls_stats)
228