1#!/usr/bin/python3
2# Regenerate <arch-syscall.h> and update syscall-names.list.
3# Copyright (C) 2020-2021 Free Software Foundation, Inc.
4# This file is part of the GNU C Library.
5#
6# The GNU C Library is free software; you can redistribute it and/or
7# modify it under the terms of the GNU Lesser General Public
8# License as published by the Free Software Foundation; either
9# version 2.1 of the License, or (at your option) any later version.
10#
11# The GNU C Library is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14# Lesser General Public License for more details.
15#
16# You should have received a copy of the GNU Lesser General Public
17# License along with the GNU C Library; if not, see
18# <http://www.gnu.org/licenses/>.
19
20import argparse
21import io
22import os
23import sys
24
25import glibcextract
26import glibcsyscalls
27
28def atomic_replace(path, contents):
29    """Atomically replace PATH with CONTENTS, via a temporary file.
30
31    The name of the temporary file is predictable, so locking is
32    required to avoid corruption.
33
34    """
35    path_tmp = path + 'T'
36    with open(path_tmp, 'w') as tmp:
37        tmp.write(contents)
38    ok = False
39    try:
40        os.rename(path_tmp, path)
41        ok = True
42    finally:
43        # On error, try to delete the temporary file.
44        if not ok:
45            try:
46                os.unlink(path_tmp)
47            except:
48                pass
49
50def main():
51    """The main entry point."""
52    parser = argparse.ArgumentParser(
53        description='System call list consistency checks')
54    parser.add_argument('--cc', metavar='CC', required=True,
55                        help='C compiler (including options) to use')
56    parser.add_argument('--lock', metavar='PATH', required=True,
57                        help='file to lock during the updates')
58    parser.add_argument('arch_syscall', metavar='ARCH-SYSCALL-H',
59                        help='The <arch-syscall.h> file to update')
60    parser.add_argument('names_list', metavar='SYSCALL-NAMES-LIST',
61                        help='The syscall name list to update ')
62
63    args = parser.parse_args()
64
65    kernel_constants = glibcsyscalls.kernel_constants(args.cc)
66
67    with open(args.lock, 'r+') as lockfile:
68        os.lockf(lockfile.fileno(), os.F_LOCK, 0)
69
70        # Replace <arch-syscall.h> with data derived from kernel headers.
71        # No merging is necessary here.  Arch-specific changes should go
72        # into <fixup-unistd-asm.h>.
73        out = io.StringIO()
74        out.write('/* AUTOGENERATED by update-syscall-lists.py.  */\n')
75        for name, value in sorted(kernel_constants.items()):
76            out.write('#define __NR_{} {}\n'.format(name, value))
77        atomic_replace(args.arch_syscall, out.getvalue())
78
79        # Merge the architecture-specific system call names into the
80        # global names list, syscall-names.list.  This file contains names
81        # from other architectures (and comments), so it is necessary to
82        # merge the existing files with the names obtained from the
83        # kernel.
84        with open(args.names_list, 'r') as list_file:
85            names_list = glibcsyscalls.SyscallNamesList(list_file)
86        merged = names_list.merge(kernel_constants.keys())
87        out = io.StringIO()
88        for line in merged:
89            out.write(line)
90        atomic_replace(args.names_list, out.getvalue())
91
92if __name__ == '__main__':
93    main()
94