diff options
Diffstat (limited to 'sysdeps')
-rw-r--r-- | sysdeps/unix/sysv/linux/Makefile | 111 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/filter-nr-syscalls.awk | 35 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/gen-syscall-h.awk | 81 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/syscall-names.list | 601 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/tst-syscall-list.sh | 99 |
5 files changed, 859 insertions, 68 deletions
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index 9d6a2de870..e571fe2efe 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -52,75 +52,50 @@ sysdep_headers += sys/mount.h sys/acct.h sys/sysctl.h \ tests += tst-clone tst-clone2 tst-clone3 tst-fanotify tst-personality \ tst-quota tst-sync_file_range test-errno-linux -# Generate the list of SYS_* macros for the system calls (__NR_* macros). - -# If there is more than one syscall list for different architecture -# variants, the CPU/Makefile defines abi-variants to be a list of names -# for those variants (e.g. 32 64), and, for each variant, defines -# abi-$(variant)-options to be compiler options to cause <asm/unistd.h> -# to define the desired list of syscalls and abi-$(variant)-condition to -# be the condition for those options to use in a C #if condition. -# abi-includes may be defined to a list of headers to include -# in the generated header, if the default does not suffice. -# -# The generated header is compiled with `-ffreestanding' to avoid any -# circular dependencies against the installed implementation headers. -# Such a dependency would require the implementation header to be -# installed before the generated header could be built (See bug 15711). -# In current practice the generated header dependencies do not include -# any of the implementation headers removed by the use of `-ffreestanding'. - -$(objpfx)bits/syscall%h $(objpfx)bits/syscall%d: ../sysdeps/unix/sysv/linux/sys/syscall.h +# Generate the list of SYS_* macros for the system calls (__NR_* +# macros). The file syscall-names.list contains all possible system +# call names, and the generated header file produces SYS_* macros for +# the __NR_* macros which are actually defined. + +generated += bits/syscall.h +$(objpfx)bits/syscall.h: \ + ../sysdeps/unix/sysv/linux/gen-syscall-h.awk \ + ../sysdeps/unix/sysv/linux/syscall-names.list $(make-target-directory) - { \ - echo '/* Generated at libc build time from kernel syscall list. */';\ - echo ''; \ - echo '#ifndef _SYSCALL_H'; \ - echo '# error "Never use <bits/syscall.h> directly; include <sys/syscall.h> instead."'; \ - echo '#endif'; \ - echo ''; \ - $(foreach h,$(abi-includes), echo '#include <$(h)>';) \ - echo ''; \ - $(if $(abi-variants), \ - $(foreach v,$(abi-variants),\ - $(CC) -ffreestanding -E -MD -MP -MF $(@:.h=.d)-t$(v) -MT '$(@:.d=.h) $(@:.h=.d)' \ - -x c $(sysincludes) $< $(abi-$(v)-options) \ - -D_LIBC -dM | \ - sed -n 's@^#define __NR_\([^ ]*\) .*$$@#define SYS_\1 __NR_\1@p' | \ - LC_ALL=C sort > $(@:.d=.h).new$(v); \ - $(if $(abi-$(v)-condition),\ - echo '#if $(abi-$(v)-condition)';) \ - cat $(@:.d=.h).new$(v); \ - $(if $(abi-$(v)-condition),echo '#endif';) \ - rm -f $(@:.d=.h).new$(v); \ - ), \ - $(CC) -ffreestanding -E -MD -MP -MF $(@:.h=.d)-t$(v) -MT '$(@:.d=.h) $(@:.h=.d)' \ - -x c $(sysincludes) $< \ - -D_LIBC -dM | \ - sed -n 's@^#define __NR_\([^ ]*\) .*$$@#define SYS_\1 __NR_\1@p' | \ - LC_ALL=C sort;) \ - } > $(@:.d=.h).new - mv -f $(@:.d=.h).new $(@:.d=.h) -ifdef abi-variants -ifneq (,$(objpfx)) - sed $(sed-remove-objpfx) \ - $(foreach v,$(abi-variants),$(@:.h=.d)-t$(v)) > $(@:.h=.d)-t3 -else - cat $(foreach v,$(abi-variants),$(@:.h=.d)-t$(v)) \ - > $(@:.h=.d)-t3 -endif - rm -f $(foreach v,$(abi-variants),$(@:.h=.d)-t$(v)) - mv -f $(@:.h=.d)-t3 $(@:.h=.d) -else - mv -f $(@:.h=.d)-t $(@:.h=.d) -endif - -ifndef no_deps -# Get the generated list of dependencies (probably /usr/include/asm/unistd.h). --include $(objpfx)bits/syscall.d -endif -generated += bits/syscall.h bits/syscall.d -endif + LC_ALL=C $(AWK) -f $^ > $@-tmp + $(move-if-change) $@-tmp $@ +before-compile += $(objpfx)bits/syscall.h + +# All macros defined by <sys/syscall.h>. Include <bits/syscall.h> +# explicitly because <sys/sycall.h> skips it if _LIBC is defined. +$(objpfx)tst-syscall-list-macros.list: \ + $(objpfx)bits/syscall.h ../sysdeps/unix/sysv/linux/sys/syscall.h + printf '#include <linux/version.h>\n\ +#include <sys/syscall.h>\n#include <bits/syscall.h>\n' | \ + $(CC) -E -o $@-tmp $(CFLAGS) $(CPPFLAGS) -x c - -dM + $(move-if-change) $@-tmp $@ + +# __NR_* system call names. Used by the test below. +$(objpfx)tst-syscall-list-nr.list: \ + ../sysdeps/unix/sysv/linux/filter-nr-syscalls.awk \ + $(objpfx)tst-syscall-list-macros.list + LC_ALL=C $(AWK) -f $^ > $@-tmp + $(move-if-change) $@-tmp $@ + +# SYS_* system call names. Used by the test below. +$(objpfx)tst-syscall-list-sys.list: $(objpfx)tst-syscall-list-macros.list + LC_ALL=C $(AWK) '/^#define SYS_/ { print substr($$2, 5) }' $< > $@-tmp + $(move-if-change) $@-tmp $@ + +tests-special += $(objpfx)tst-syscall-list.out +$(objpfx)tst-syscall-list.out: \ + ../sysdeps/unix/sysv/linux/tst-syscall-list.sh \ + $(objpfx)tst-syscall-list-macros.list \ + $(objpfx)tst-syscall-list-nr.list \ + $(objpfx)tst-syscall-list-sys.list + $(BASH) $^ $(AWK) > $@; $(evaluate-test) + +endif # $(subdir) == misc ifeq ($(subdir),time) sysdep_headers += sys/timex.h bits/timex.h diff --git a/sysdeps/unix/sysv/linux/filter-nr-syscalls.awk b/sysdeps/unix/sysv/linux/filter-nr-syscalls.awk new file mode 100644 index 0000000000..15b052a9c9 --- /dev/null +++ b/sysdeps/unix/sysv/linux/filter-nr-syscalls.awk @@ -0,0 +1,35 @@ +# Filter preprocessor __NR_* macros and extract system call names. +# Copyright (C) 2017 Free Software Foundation, Inc. +# This file is part of the GNU C Library. +# +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# The GNU C Library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# <http://www.gnu.org/licenses/>. + +# Skip reserved system calls. +/^#define __NR_(unused|reserved)[0-9]+ / { + next; +} + +# Skip pseudo-system calls which describe ranges. +/^#define __NR_(syscalls|arch_specific_syscall|(OABI_)?SYSCALL_BASE) / { + next; +} +/^#define __NR_(|64_|[NO]32_)Linux(_syscalls)? / { + next; +} + +# Print the remaining _NR_* macros as system call names. +/^#define __NR_/ { + print substr($2, 6); +} diff --git a/sysdeps/unix/sysv/linux/gen-syscall-h.awk b/sysdeps/unix/sysv/linux/gen-syscall-h.awk new file mode 100644 index 0000000000..ef8eb6be52 --- /dev/null +++ b/sysdeps/unix/sysv/linux/gen-syscall-h.awk @@ -0,0 +1,81 @@ +# Generate SYS_* macros from a list in a text file. +# Copyright (C) 2017 Free Software Foundation, Inc. +# This file is part of the GNU C Library. +# +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# The GNU C Library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# <http://www.gnu.org/licenses/>. + +# Emit a conditional definition for SYS_NAME. +function emit(name) { + print "#ifdef __NR_" name; + print "# define SYS_" name " __NR_" name; + print "#endif"; + print ""; +} + +# Bail out with an error. +function fatal(message) { + print FILENAME ":" FNR ": " message > "/dev/stderr"; + exit 1; +} + +BEGIN { + name = ""; + kernel = ""; +} + +# Skip empty lines and comments. +/^\s*(|#.*)$/ { + next; +} + +# Kernel version. Used for documentation purposes only. +/^kernel [0-9.]+$/ { + if (kernel != "") { + fatal("duplicate kernel directive"); + } + kernel = $2; + print "/* Generated at libc build time from syscall list. */"; + print "/* The system call list corresponds to kernel " kernel ". */"; + print ""; + print "#ifndef _SYSCALL_H" + print "# error \"Never use <bits/syscall.h> directly; include <sys/syscall.h> instead.\""; + print "#endif"; + print ""; + split($2, kernel_version, "."); + kernel_major = kernel_version[1]; + kernel_minor = kernel_version[2]; + kernel_version_code = kernel_major * 65536 + kernel_minor * 256; + print "#define __GLIBC_LINUX_VERSION_CODE " kernel_version_code; + print ""; + next; +} + +# If there is just one word, it is a system call. +/^[a-zA-Z_][a-zA-Z0-9_]+$/ { + if (kernel == "") { + fatal("expected kernel directive before this line"); + } + if ($1 <= name) { + fatal("name " name " violates ordering"); + } + emit($1); + name = $1; + next; +} + +# The rest has to be syntax errors. +// { + fatal("unrecognized syntax"); +} diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list new file mode 100644 index 0000000000..2e5cc77fe0 --- /dev/null +++ b/sysdeps/unix/sysv/linux/syscall-names.list @@ -0,0 +1,601 @@ +# List of all known Linux system calls. +# Copyright (C) 2017 Free Software Foundation, Inc. +# This file is part of the GNU C Library. +# +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# The GNU C Library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# <http://www.gnu.org/licenses/>. + +# This file contains the list of system call names names. It has to +# remain in alphabetica order. Lines which start with # are treated +# as comments. This file can list all potential system calls. The +# names are only used if the installed kernel headers also provide +# them. + +# The list of system calls is current as of Linux 4.12. +kernel 4.12 + +FAST_atomic_update +FAST_cmpxchg +FAST_cmpxchg64 +_llseek +_newselect +_sysctl +accept +accept4 +access +acct +acl_get +acl_set +add_key +adjtimex +afs_syscall +alarm +alloc_hugepages +arch_prctl +arm_fadvise64_64 +arm_sync_file_range +atomic_barrier +atomic_cmpxchg_32 +attrctl +bdflush +bind +bpf +break +brk +cachectl +cacheflush +capget +capset +chdir +chmod +chown +chown32 +chroot +clock_adjtime +clock_getres +clock_gettime +clock_nanosleep +clock_settime +clone +clone2 +close +cmpxchg_badaddr +connect +copy_file_range +creat +create_module +delete_module +dipc +dup +dup2 +dup3 +epoll_create +epoll_create1 +epoll_ctl +epoll_ctl_old +epoll_pwait +epoll_wait +epoll_wait_old +eventfd +eventfd2 +exec_with_loader +execv +execve +execveat +exit +exit_group +faccessat +fadvise64 +fadvise64_64 +fallocate +fanotify_init +fanotify_mark +fchdir +fchmod +fchmodat +fchown +fchown32 +fchownat +fcntl +fcntl64 +fdatasync +fgetxattr +finit_module +flistxattr +flock +fork +free_hugepages +fremovexattr +fsetxattr +fstat +fstat64 +fstatat64 +fstatfs +fstatfs64 +fsync +ftime +ftruncate +ftruncate64 +futex +futimesat +get_kernel_syms +get_mempolicy +get_robust_list +get_thread_area +getcpu +getcwd +getdents +getdents64 +getdomainname +getdtablesize +getegid +getegid32 +geteuid +geteuid32 +getgid +getgid32 +getgroups +getgroups32 +gethostname +getitimer +getpagesize +getpeername +getpgid +getpgrp +getpid +getpmsg +getppid +getpriority +getrandom +getresgid +getresgid32 +getresuid +getresuid32 +getrlimit +getrusage +getsid +getsockname +getsockopt +gettid +gettimeofday +getuid +getuid32 +getunwind +getxattr +getxgid +getxpid +getxuid +gtty +idle +init_module +inotify_add_watch +inotify_init +inotify_init1 +inotify_rm_watch +io_cancel +io_destroy +io_getevents +io_setup +io_submit +ioctl +ioperm +iopl +ioprio_get +ioprio_set +ipc +kcmp +kern_features +kexec_file_load +kexec_load +keyctl +kill +lchown +lchown32 +lgetxattr +link +linkat +listen +listxattr +llistxattr +llseek +lock +lookup_dcookie +lremovexattr +lseek +lsetxattr +lstat +lstat64 +madvise +mbind +membarrier +memfd_create +memory_ordering +migrate_pages +mincore +mkdir +mkdirat +mknod +mknodat +mlock +mlock2 +mlockall +mmap +mmap2 +modify_ldt +mount +move_pages +mprotect +mpx +mq_getsetattr +mq_notify +mq_open +mq_timedreceive +mq_timedsend +mq_unlink +mremap +msgctl +msgget +msgrcv +msgsnd +msync +multiplexer +munlock +munlockall +munmap +name_to_handle_at +nanosleep +newfstatat +nfsservctl +ni_syscall +nice +old_adjtimex +oldfstat +oldlstat +oldolduname +oldstat +oldumount +olduname +open +open_by_handle_at +openat +osf_adjtime +osf_afs_syscall +osf_alt_plock +osf_alt_setsid +osf_alt_sigpending +osf_asynch_daemon +osf_audcntl +osf_audgen +osf_chflags +osf_execve +osf_exportfs +osf_fchflags +osf_fdatasync +osf_fpathconf +osf_fstat +osf_fstatfs +osf_fstatfs64 +osf_fuser +osf_getaddressconf +osf_getdirentries +osf_getdomainname +osf_getfh +osf_getfsstat +osf_gethostid +osf_getitimer +osf_getlogin +osf_getmnt +osf_getrusage +osf_getsysinfo +osf_gettimeofday +osf_kloadcall +osf_kmodcall +osf_lstat +osf_memcntl +osf_mincore +osf_mount +osf_mremap +osf_msfs_syscall +osf_msleep +osf_mvalid +osf_mwakeup +osf_naccept +osf_nfssvc +osf_ngetpeername +osf_ngetsockname +osf_nrecvfrom +osf_nrecvmsg +osf_nsendmsg +osf_ntp_adjtime +osf_ntp_gettime +osf_old_creat +osf_old_fstat +osf_old_getpgrp +osf_old_killpg +osf_old_lstat +osf_old_open +osf_old_sigaction +osf_old_sigblock +osf_old_sigreturn +osf_old_sigsetmask +osf_old_sigvec +osf_old_stat +osf_old_vadvise +osf_old_vtrace +osf_old_wait +osf_oldquota +osf_pathconf +osf_pid_block +osf_pid_unblock +osf_plock +osf_priocntlset +osf_profil +osf_proplist_syscall +osf_reboot +osf_revoke +osf_sbrk +osf_security +osf_select +osf_set_program_attributes +osf_set_speculative +osf_sethostid +osf_setitimer +osf_setlogin +osf_setsysinfo +osf_settimeofday +osf_shmat +osf_signal +osf_sigprocmask +osf_sigsendset +osf_sigstack +osf_sigwaitprim +osf_sstk +osf_stat +osf_statfs +osf_statfs64 +osf_subsys_info +osf_swapctl +osf_swapon +osf_syscall +osf_sysinfo +osf_table +osf_uadmin +osf_usleep_thread +osf_uswitch +osf_utc_adjtime +osf_utc_gettime +osf_utimes +osf_utsname +osf_wait4 +osf_waitid +pause +pciconfig_iobase +pciconfig_read +pciconfig_write +perf_event_open +perfctr +perfmonctl +personality +pipe +pipe2 +pivot_root +pkey_alloc +pkey_free +pkey_mprotect +poll +ppoll +prctl +pread64 +preadv +preadv2 +prlimit64 +process_vm_readv +process_vm_writev +prof +profil +pselect6 +ptrace +putpmsg +pwrite64 +pwritev +pwritev2 +query_module +quotactl +read +readahead +readdir +readlink +readlinkat +readv +reboot +recv +recvfrom +recvmmsg +recvmsg +remap_file_pages +removexattr +rename +renameat +renameat2 +request_key +restart_syscall +rmdir +rt_sigaction +rt_sigpending +rt_sigprocmask +rt_sigqueueinfo +rt_sigreturn +rt_sigsuspend +rt_sigtimedwait +rt_tgsigqueueinfo +rtas +s390_guarded_storage +s390_pci_mmio_read +s390_pci_mmio_write +s390_runtime_instr +sched_get_affinity +sched_get_priority_max +sched_get_priority_min +sched_getaffinity +sched_getattr +sched_getparam +sched_getscheduler +sched_rr_get_interval +sched_set_affinity +sched_setaffinity +sched_setattr +sched_setparam +sched_setscheduler +sched_yield +seccomp +security +select +semctl +semget +semop +semtimedop +send +sendfile +sendfile64 +sendmmsg +sendmsg +sendto +set_mempolicy +set_robust_list +set_thread_area +set_tid_address +setdomainname +setfsgid +setfsgid32 +setfsuid +setfsuid32 +setgid +setgid32 +setgroups +setgroups32 +sethae +sethostname +setitimer +setns +setpgid +setpgrp +setpriority +setregid +setregid32 +setresgid +setresgid32 +setresuid +setresuid32 +setreuid +setreuid32 +setrlimit +setsid +setsockopt +settimeofday +setuid +setuid32 +setxattr +sgetmask +shmat +shmctl +shmdt +shmget +shutdown +sigaction +sigaltstack +signal +signalfd +signalfd4 +sigpending +sigprocmask +sigreturn +sigsuspend +socket +socketcall +socketpair +splice +spu_create +spu_run +ssetmask +stat +stat64 +statfs +statfs64 +statx +stime +stty +subpage_prot +swapcontext +swapoff +swapon +switch_endian +symlink +symlinkat +sync +sync_file_range +sync_file_range2 +syncfs +sys_debug_setcontext +sys_epoll_create +sys_epoll_ctl +sys_epoll_wait +syscall +sysfs +sysinfo +syslog +sysmips +tee +tgkill +time +timer_create +timer_delete +timer_getoverrun +timer_gettime +timer_settime +timerfd +timerfd_create +timerfd_gettime +timerfd_settime +times +tkill +truncate +truncate64 +tuxcall +ugetrlimit +ulimit +umask +umount +umount2 +uname +unlink +unlinkat +unshare +uselib +userfaultfd +ustat +utime +utimensat +utimes +utrap_install +vfork +vhangup +vm86 +vm86old +vmsplice +vserver +wait4 +waitid +waitpid +write +writev diff --git a/sysdeps/unix/sysv/linux/tst-syscall-list.sh b/sysdeps/unix/sysv/linux/tst-syscall-list.sh new file mode 100644 index 0000000000..8474cf888f --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-syscall-list.sh @@ -0,0 +1,99 @@ +#!/bin/bash +# Consistency checks for the system call list +# Copyright (C) 2017 Free Software Foundation, Inc. +# This file is part of the GNU C Library. +# +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# The GNU C Library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# <http://www.gnu.org/licenses/>. + +export LC_ALL=C +set -e +set -o pipefail + +if test $# != 4; then + echo "error: wrong number of arguments: $#" + exit 1 +fi + +macros="$1" +list_nr="$2" +list_sys="$3" +GAWK="$4" + +linux_version="$("$GAWK" \ + '/#define LINUX_VERSION_CODE / {print $3}' < "$macros")" +glibc_linux_version="$("$GAWK" \ + '/#define __GLIBC_LINUX_VERSION_CODE / {print $3}' < "$macros")" + +echo "info: LINUX_VERSION_CODE: $linux_version" +echo "info: __GLIBC_LINUX_VERSION_CODE: $glibc_linux_version" +# Ignore the subrelease in the comparison. +if test $(expr "$glibc_linux_version" / 256) \ + -lt $(expr "$linux_version" / 256); then + echo "info: The kernel major/minor version is newer than the glibc version" + kernel_newer=true +else + kernel_newer=false +fi +echo + +errors=0 + +# Use getpid as a system call which is expected to be always defined. +# alpha uses getxpid instead, so it is permitted as an alternative. +if ! grep -E -q '^getx?pid$' -- "$list_nr"; then + echo "error: __NR_getpid not defined" + errors=1 +fi +if ! grep -E -q '^getx?pid$' -- "$list_sys"; then + echo "error: SYS_getpid not defined" + errors=1 +fi + +comm_1="$(mktemp)" +comm_2="$(mktemp)" +comm_result="$(mktemp)" +cleanup () { + rm -f -- "$comm_1" "$comm_2" "$comm_result" +} +trap cleanup 0 + +sort -o "$comm_1" -- "$list_nr" +sort -o "$comm_2" -- "$list_sys" + +# Check for missing SYS_* macros. +comm --check-order -2 -3 -- "$comm_1" "$comm_2" > "$comm_result" +if test -s "$comm_result"; then + echo "error: These system calls need to be added to syscall-names.list:" + cat -- "$comm_result" + # This is only an error if our version is older than the kernel + # version because we cannot predict future kernel development. + if $kernel_newer; then + echo + echo "warning: This error has been ignored because the glibc" + echo "warning: system call list is older than the kernel version." + else + errors=1 + fi +fi + +# Check for additional SYS_* macros. +comm --check-order -1 -3 -- "$comm_1" "$comm_2" > "$comm_result" +if test -s "$comm_result"; then + echo "error: The following system calls have unexpected SYS_* macros:" + cat -- "$comm_result" + errors=1 +fi + +exit "$errors" |