1  #!/usr/bin/python3
       2  # Regenerate <arch-syscall.h> and update syscall-names.list.
       3  # Copyright (C) 2020-2023 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  
      20  import argparse
      21  import io
      22  import os
      23  import sys
      24  
      25  import glibcextract
      26  import glibcsyscalls
      27  
      28  def 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  
      50  def 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  
      92  if __name__ == '__main__':
      93      main()