#!/usr/bin/env bash
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

# This script runs or (given -n) prints suggested commands to generate files for
# the Architecture/OS specified by the GOARCH and GOOS environment variables.
# See README.md for more information about how the build system works.

GOOSARCH="${GOOS}_${GOARCH}"

# defaults
mksyscall="./mksyscall.pl"
mkerrors="./mkerrors.sh"
zerrors="zerrors_$GOOSARCH.go"
mksysctl=""
zsysctl="zsysctl_$GOOSARCH.go"
mksysnum=
mktypes=
run="sh"
cmd=""

case "$1" in
-syscalls)
	for i in zsyscall*go
	do
		# Run the command line that appears in the first line
		# of the generated file to regenerate it.
		sed 1q $i | sed 's;^// ;;' | sh > _$i && gofmt < _$i > $i
		rm _$i
	done
	exit 0
	;;
-n)
	run="cat"
	cmd="echo"
	shift
esac

case "$#" in
0)
	;;
*)
	echo 'usage: mkall.sh [-n]' 1>&2
	exit 2
esac

if [[ "$GOOS" = "linux" ]] && [[ "$GOARCH" != "sparc64" ]]; then
	# Use then new build system
	# Files generated through docker (use $cmd so you can Ctl-C the build or run)
	$cmd docker build --tag generate:$GOOS $GOOS
	$cmd docker run --interactive --tty --volume $(dirname "$(readlink -f "$0")"):/build generate:$GOOS
	exit
fi

GOOSARCH_in=syscall_$GOOSARCH.go
case "$GOOSARCH" in
_* | *_ | _)
	echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
	exit 1
	;;
darwin_386)
	mkerrors="$mkerrors -m32"
	mksyscall="./mksyscall.pl -l32"
	mksysnum="./mksysnum_darwin.pl $(xcrun --show-sdk-path --sdk macosx)/usr/include/sys/syscall.h"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
darwin_amd64)
	mkerrors="$mkerrors -m64"
	mksysnum="./mksysnum_darwin.pl $(xcrun --show-sdk-path --sdk macosx)/usr/include/sys/syscall.h"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
darwin_arm)
	mkerrors="$mkerrors"
	mksysnum="./mksysnum_darwin.pl /usr/include/sys/syscall.h"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
darwin_arm64)
	mkerrors="$mkerrors -m64"
	mksysnum="./mksysnum_darwin.pl $(xcrun --show-sdk-path --sdk iphoneos)/usr/include/sys/syscall.h"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
dragonfly_386)
	mkerrors="$mkerrors -m32"
	mksyscall="./mksyscall.pl -l32 -dragonfly"
	mksysnum="curl -s 'http://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master' | ./mksysnum_dragonfly.pl"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
dragonfly_amd64)
	mkerrors="$mkerrors -m64"
	mksyscall="./mksyscall.pl -dragonfly"
	mksysnum="curl -s 'http://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master' | ./mksysnum_dragonfly.pl"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
freebsd_386)
	mkerrors="$mkerrors -m32"
	mksyscall="./mksyscall.pl -l32"
	mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
freebsd_amd64)
	mkerrors="$mkerrors -m64"
	mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
freebsd_arm)
	mkerrors="$mkerrors"
	mksyscall="./mksyscall.pl -l32 -arm"
	mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
	# Let the type of C char be signed for making the bare syscall
	# API consistent across over platforms.
	mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
	;;
linux_sparc64)
	GOOSARCH_in=syscall_linux_sparc64.go
	unistd_h=/usr/include/sparc64-linux-gnu/asm/unistd.h
	mkerrors="$mkerrors -m64"
	mksysnum="./mksysnum_linux.pl $unistd_h"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
netbsd_386)
	mkerrors="$mkerrors -m32"
	mksyscall="./mksyscall.pl -l32 -netbsd"
	mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
netbsd_amd64)
	mkerrors="$mkerrors -m64"
	mksyscall="./mksyscall.pl -netbsd"
	mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
openbsd_386)
	mkerrors="$mkerrors -m32"
	mksyscall="./mksyscall.pl -l32 -openbsd"
	mksysctl="./mksysctl_openbsd.pl"
	zsysctl="zsysctl_openbsd.go"
	mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
openbsd_amd64)
	mkerrors="$mkerrors -m64"
	mksyscall="./mksyscall.pl -openbsd"
	mksysctl="./mksysctl_openbsd.pl"
	zsysctl="zsysctl_openbsd.go"
	mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
solaris_amd64)
	mksyscall="./mksyscall_solaris.pl"
	mkerrors="$mkerrors -m64"
	mksysnum=
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
*)
	echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
	exit 1
	;;
esac

(
	if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi
	case "$GOOS" in
	*)
		syscall_goos="syscall_$GOOS.go"
		case "$GOOS" in
		darwin | dragonfly | freebsd | netbsd | openbsd)
			syscall_goos="syscall_bsd.go $syscall_goos"
			;;
		esac
		if [ -n "$mksyscall" ]; then echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go"; fi
		;;
	esac
	if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
	if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
	if [ -n "$mktypes" ]; then
		echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go";
	fi
) | $run


#!/usr/bin/env bash
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

# Generate Go code listing errors and other #defined constant
# values (ENAMETOOLONG etc.), by asking the preprocessor
# about the definitions.

unset LANG
export LC_ALL=C
export LC_CTYPE=C

if test -z "$GOARCH" -o -z "$GOOS"; then
	echo 1>&2 "GOARCH or GOOS not defined in environment"
	exit 1
fi

# Check that we are using the new build system if we should
if [[ "$GOOS" -eq "linux" ]] && [[ "$GOARCH" != "sparc64" ]]; then
	if [[ "$GOLANG_SYS_BUILD" -ne "docker" ]]; then
		echo 1>&2 "In the new build system, mkerrors should not be called directly."
		echo 1>&2 "See README.md"
		exit 1
	fi
fi

CC=${CC:-cc}

if [[ "$GOOS" -eq "solaris" ]]; then
	# Assumes GNU versions of utilities in PATH.
	export PATH=/usr/gnu/bin:$PATH
fi

uname=$(uname)

includes_Darwin='
#define _DARWIN_C_SOURCE
#define KERNEL
#define _DARWIN_USE_64_BIT_INODE
#include <sys/types.h>
#include <sys/event.h>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <termios.h>
'

includes_DragonFly='
#include <sys/types.h>
#include <sys/event.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
#include <termios.h>
#include <netinet/ip.h>
#include <net/ip_mroute/ip_mroute.h>
'

includes_FreeBSD='
#include <sys/param.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
#include <termios.h>
#include <netinet/ip.h>
#include <netinet/ip_mroute.h>
#include <sys/extattr.h>

#if __FreeBSD__ >= 10
#define IFT_CARP	0xf8	// IFT_CARP is deprecated in FreeBSD 10
#undef SIOCAIFADDR
#define SIOCAIFADDR	_IOW(105, 26, struct oifaliasreq)	// ifaliasreq contains if_data
#undef SIOCSIFPHYADDR
#define SIOCSIFPHYADDR	_IOW(105, 70, struct oifaliasreq)	// ifaliasreq contains if_data
#endif
'

includes_Linux='
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#ifndef __LP64__
#define _FILE_OFFSET_BITS 64
#endif
#define _GNU_SOURCE

// <sys/ioctl.h> is broken on powerpc64, as it fails to include definitions of
// these structures. We just include them copied from <bits/termios.h>.
#if defined(__powerpc__)
struct sgttyb {
        char    sg_ispeed;
        char    sg_ospeed;
        char    sg_erase;
        char    sg_kill;
        short   sg_flags;
};

struct tchars {
        char    t_intrc;
        char    t_quitc;
        char    t_startc;
        char    t_stopc;
        char    t_eofc;
        char    t_brkc;
};

struct ltchars {
        char    t_suspc;
        char    t_dsuspc;
        char    t_rprntc;
        char    t_flushc;
        char    t_werasc;
        char    t_lnextc;
};
#endif

#include <bits/sockaddr.h>
#include <sys/epoll.h>
#include <sys/inotify.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_alg.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/if_tun.h>
#include <linux/if_packet.h>
#include <linux/if_addr.h>
#include <linux/falloc.h>
#include <linux/filter.h>
#include <linux/fs.h>
#include <linux/keyctl.h>
#include <linux/netlink.h>
#include <linux/random.h>
#include <linux/reboot.h>
#include <linux/rtnetlink.h>
#include <linux/ptrace.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/icmpv6.h>
#include <linux/serial.h>
#include <linux/can.h>
#include <linux/vm_sockets.h>
#include <net/route.h>
#include <asm/termbits.h>

#ifndef MSG_FASTOPEN
#define MSG_FASTOPEN    0x20000000
#endif

#ifndef PTRACE_GETREGS
#define PTRACE_GETREGS	0xc
#endif

#ifndef PTRACE_SETREGS
#define PTRACE_SETREGS	0xd
#endif

#ifndef SOL_NETLINK
#define SOL_NETLINK	270
#endif

#ifdef SOL_BLUETOOTH
// SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h
// but it is already in bluetooth_linux.go
#undef SOL_BLUETOOTH
#endif

// Certain constants are missing from the fs/crypto UAPI
#define FS_KEY_DESC_PREFIX              "fscrypt:"
#define FS_KEY_DESC_PREFIX_SIZE         8
#define FS_MAX_KEY_SIZE                 64
'

includes_NetBSD='
#include <sys/types.h>
#include <sys/param.h>
#include <sys/event.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/termios.h>
#include <sys/ttycom.h>
#include <sys/wait.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_mroute.h>
#include <netinet/if_ether.h>

// Needed since <sys/param.h> refers to it...
#define schedppq 1
'

includes_OpenBSD='
#include <sys/types.h>
#include <sys/param.h>
#include <sys/event.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/termios.h>
#include <sys/ttycom.h>
#include <sys/wait.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/if_var.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_mroute.h>
#include <netinet/if_ether.h>
#include <net/if_bridge.h>

// We keep some constants not supported in OpenBSD 5.5 and beyond for
// the promise of compatibility.
#define EMUL_ENABLED		0x1
#define EMUL_NATIVE		0x2
#define IPV6_FAITH		0x1d
#define IPV6_OPTIONS		0x1
#define IPV6_RTHDR_STRICT	0x1
#define IPV6_SOCKOPT_RESERVED1	0x3
#define SIOCGIFGENERIC		0xc020693a
#define SIOCSIFGENERIC		0x80206939
#define WALTSIG			0x4
'

includes_SunOS='
#include <limits.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
#include <termios.h>
#include <netinet/ip.h>
#include <netinet/ip_mroute.h>
'

includes='
#include <sys/types.h>
#include <sys/file.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <sys/signal.h>
#include <signal.h>
#include <sys/resource.h>
#include <time.h>
'
ccflags="$@"

# Write go tool cgo -godefs input.
(
	echo package unix
	echo
	echo '/*'
	indirect="includes_$(uname)"
	echo "${!indirect} $includes"
	echo '*/'
	echo 'import "C"'
	echo 'import "syscall"'
	echo
	echo 'const ('

	# The gcc command line prints all the #defines
	# it encounters while processing the input
	echo "${!indirect} $includes" | $CC -x c - -E -dM $ccflags |
	awk '
		$1 != "#define" || $2 ~ /\(/ || $3 == "" {next}

		$2 ~ /^E([ABCD]X|[BIS]P|[SD]I|S|FL)$/ {next}  # 386 registers
		$2 ~ /^(SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))/ {next}
		$2 ~ /^(SCM_SRCRT)$/ {next}
		$2 ~ /^(MAP_FAILED)$/ {next}
		$2 ~ /^ELF_.*$/ {next}# <asm/elf.h> contains ELF_ARCH, etc.

		$2 ~ /^EXTATTR_NAMESPACE_NAMES/ ||
		$2 ~ /^EXTATTR_NAMESPACE_[A-Z]+_STRING/ {next}

		$2 !~ /^ETH_/ &&
		$2 !~ /^EPROC_/ &&
		$2 !~ /^EQUIV_/ &&
		$2 !~ /^EXPR_/ &&
		$2 ~ /^E[A-Z0-9_]+$/ ||
		$2 ~ /^B[0-9_]+$/ ||
		$2 == "BOTHER" ||
		$2 ~ /^CI?BAUD(EX)?$/ ||
		$2 == "IBSHIFT" ||
		$2 ~ /^V[A-Z0-9]+$/ ||
		$2 ~ /^CS[A-Z0-9]/ ||
		$2 ~ /^I(SIG|CANON|CRNL|UCLC|EXTEN|MAXBEL|STRIP|UTF8)$/ ||
		$2 ~ /^IGN/ ||
		$2 ~ /^IX(ON|ANY|OFF)$/ ||
		$2 ~ /^IN(LCR|PCK)$/ ||
		$2 ~ /(^FLU?SH)|(FLU?SH$)/ ||
		$2 ~ /^C(LOCAL|READ|MSPAR|RTSCTS)$/ ||
		$2 == "BRKINT" ||
		$2 == "HUPCL" ||
		$2 == "PENDIN" ||
		$2 == "TOSTOP" ||
		$2 == "XCASE" ||
		$2 == "ALTWERASE" ||
		$2 == "NOKERNINFO" ||
		$2 ~ /^PAR/ ||
		$2 ~ /^SIG[^_]/ ||
		$2 ~ /^O[CNPFPL][A-Z]+[^_][A-Z]+$/ ||
		$2 ~ /^(NL|CR|TAB|BS|VT|FF)DLY$/ ||
		$2 ~ /^(NL|CR|TAB|BS|VT|FF)[0-9]$/ ||
		$2 ~ /^O?XTABS$/ ||
		$2 ~ /^TC[IO](ON|OFF)$/ ||
		$2 ~ /^IN_/ ||
		$2 ~ /^LOCK_(SH|EX|NB|UN)$/ ||
		$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|ICMP6|TCP|EVFILT|NOTE|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|MCL|DT|MADV|PR)_/ ||
		$2 ~ /^FALLOC_/ ||
		$2 == "ICMPV6_FILTER" ||
		$2 == "SOMAXCONN" ||
		$2 == "NAME_MAX" ||
		$2 == "IFNAMSIZ" ||
		$2 ~ /^CTL_(MAXNAME|NET|QUERY)$/ ||
		$2 ~ /^SYSCTL_VERS/ ||
		$2 ~ /^(MS|MNT)_/ ||
		$2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ ||
		$2 ~ /^(O|F|FD|NAME|S|PTRACE|PT)_/ ||
		$2 ~ /^LINUX_REBOOT_CMD_/ ||
		$2 ~ /^LINUX_REBOOT_MAGIC[12]$/ ||
		$2 !~ "NLA_TYPE_MASK" &&
		$2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P)_/ ||
		$2 ~ /^SIOC/ ||
		$2 ~ /^TIOC/ ||
		$2 ~ /^TCGET/ ||
		$2 ~ /^TCSET/ ||
		$2 ~ /^TC(FLSH|SBRKP?|XONC)$/ ||
		$2 !~ "RTF_BITS" &&
		$2 ~ /^(IFF|IFT|NET_RT|RTM|RTF|RTV|RTA|RTAX)_/ ||
		$2 ~ /^BIOC/ ||
		$2 ~ /^RUSAGE_(SELF|CHILDREN|THREAD)/ ||
		$2 ~ /^RLIMIT_(AS|CORE|CPU|DATA|FSIZE|NOFILE|STACK)|RLIM_INFINITY/ ||
		$2 ~ /^PRIO_(PROCESS|PGRP|USER)/ ||
		$2 ~ /^CLONE_[A-Z_]+/ ||
		$2 !~ /^(BPF_TIMEVAL)$/ &&
		$2 ~ /^(BPF|DLT)_/ ||
		$2 ~ /^CLOCK_/ ||
		$2 ~ /^CAN_/ ||
		$2 ~ /^ALG_/ ||
		$2 ~ /^FS_(POLICY_FLAGS|KEY_DESC|ENCRYPTION_MODE|[A-Z0-9_]+_KEY_SIZE|IOC_(GET|SET)_ENCRYPTION)/ ||
		$2 ~ /^GRND_/ ||
		$2 ~ /^KEY_(SPEC|REQKEY_DEFL)_/ ||
		$2 ~ /^KEYCTL_/ ||
		$2 ~ /^SPLICE_/ ||
		$2 ~ /^(VM|VMADDR)_/ ||
		$2 !~ "WMESGLEN" &&
		$2 ~ /^W[A-Z0-9]+$/ ||
		$2 ~ /^BLK[A-Z]*(GET$|SET$|BUF$|PART$|SIZE)/ {printf("\t%s = C.%s\n", $2, $2)}
		$2 ~ /^__WCOREFLAG$/ {next}
		$2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)}

		{next}
	' | sort

	echo ')'
) >_const.go

# Pull out the error names for later.
errors=$(
	echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
	awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print $2 }' |
	sort
)

# Pull out the signal names for later.
signals=$(
	echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
	awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' |
	egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' |
	sort
)

# Again, writing regexps to a file.
echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
	awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print "^\t" $2 "[ \t]*=" }' |
	sort >_error.grep
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
	awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' |
	egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' |
	sort >_signal.grep

echo '// mkerrors.sh' "$@"
echo '// Code generated by the command above; see README.md. DO NOT EDIT.'
echo
echo "// +build ${GOARCH},${GOOS}"
echo
go tool cgo -godefs -- "$@" _const.go >_error.out
cat _error.out | grep -vf _error.grep | grep -vf _signal.grep
echo
echo '// Errors'
echo 'const ('
cat _error.out | grep -f _error.grep | sed 's/=\(.*\)/= syscall.Errno(\1)/'
echo ')'

echo
echo '// Signals'
echo 'const ('
cat _error.out | grep -f _signal.grep | sed 's/=\(.*\)/= syscall.Signal(\1)/'
echo ')'

# Run C program to print error and syscall strings.
(
	echo -E "
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <signal.h>

#define nelem(x) (sizeof(x)/sizeof((x)[0]))

enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below

int errors[] = {
"
	for i in $errors
	do
		echo -E '	'$i,
	done

	echo -E "
};

int signals[] = {
"
	for i in $signals
	do
		echo -E '	'$i,
	done

	# Use -E because on some systems bash builtin interprets \n itself.
	echo -E '
};

static int
intcmp(const void *a, const void *b)
{
	return *(int*)a - *(int*)b;
}

int
main(void)
{
	int i, e;
	char buf[1024], *p;

	printf("\n\n// Error table\n");
	printf("var errors = [...]string {\n");
	qsort(errors, nelem(errors), sizeof errors[0], intcmp);
	for(i=0; i<nelem(errors); i++) {
		e = errors[i];
		if(i > 0 && errors[i-1] == e)
			continue;
		strcpy(buf, strerror(e));
		// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
		if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
			buf[0] += a - A;
		printf("\t%d: \"%s\",\n", e, buf);
	}
	printf("}\n\n");

	printf("\n\n// Signal table\n");
	printf("var signals = [...]string {\n");
	qsort(signals, nelem(signals), sizeof signals[0], intcmp);
	for(i=0; i<nelem(signals); i++) {
		e = signals[i];
		if(i > 0 && signals[i-1] == e)
			continue;
		strcpy(buf, strsignal(e));
		// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
		if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
			buf[0] += a - A;
		// cut trailing : number.
		p = strrchr(buf, ":"[0]);
		if(p)
			*p = '\0';
		printf("\t%d: \"%s\",\n", e, buf);
	}
	printf("}\n\n");

	return 0;
}

'
) >_errors.c

$CC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.go _error.grep _signal.grep _error.out


#!/bin/bash
# Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the
# "License"). You may not use this file except in compliance
#  with the License. A copy of the License is located at
#
#     http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and
# limitations under the License.

cat > $(pwd)/logger.go <<EOF
// Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
//     http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.

// GENERATED FILE, DO NOT MODIFY BY HAND
//go:generate bundle_log_config.sh

package config

// Logger holds the bundled log configuration for seelog
func Logger() string {
	return \`
$(cat ../../seelog.xml)
\`
}
EOF


#!/bin/bash
set -e # exit on failure

fail() {
    echo ""
    echo -e "\033[0;31mInstallation Failed\033[0m" # print it in red
    exit 1
}

check-option-value() {
    if [ "${2:0:2}" == "--" ]; then
        echo "Option $1 was passed an invalid value: $2. Perhaps you passed in an empty env var?"
        fail
    fi
}

usage() {
    echo "$(basename "$0") [--help] --region REGION --activation-code CODE --activation-id ID [--cluster CLUSTER] [--enable-gpu] [--docker-install-source all|docker|distro|none] [--ecs-version VERSION] [--ecs-endpoint ENDPOINT] [--skip-registration] [--no-start]

  --help
        (optional) display this help message.
  --region string
        (required) this must match the region of your ECS cluster and SSM activation.
  --activation-id string
        (required) activation id from the create activation command. Not required if --skip-registration is specified.
  --activation-code string
        (required) activation code from the create activation command. Not required if --skip-registration is specified.
  --cluster string
        (optional) pass the cluster name that ECS agent will connect too. By default its value is 'default'.
  --enable-gpu
        (optional) if this flag is provided, GPU support for ECS will be enabled.
  --docker-install-source
        (optional) Source of docker installation. Possible values are 'all, docker, distro, none'. Defaults to 'all'.
  --ecs-version string
        (optional) Version of the ECS agent rpm/deb package to use. If not specified, default to latest.
  --skip-registration
        (optional) if this is enabled, SSM agent install and instance registration with SSM is skipped.
  --certs-file
        (optional) TLS certs for execute command feature. Defaults to searching for certs in known possible locations.
  --no-start
        (optional) if this flag is provided, SSM agent, docker and ECS agent will not be started by the script despite being installed."
}

# required:
REGION=""
ACTIVATION_CODE=""
ACTIVATION_ID=""
# optional:
SKIP_REGISTRATION=false
ECS_CLUSTER=""
DOCKER_SOURCE=""
ECS_VERSION=""
DEB_URL=""
RPM_URL=""
ECS_ENDPOINT=""
CERTS_FILE=""
# Whether to check signature for the downloaded amazon-ecs-init package. true unless --skip-gpg-check
# specified. --skip-gpg-check is mostly for testing purpose (so that we can test a custom build of ecs init package
# without having to sign it).
CHECK_SIG=true
NO_START=false
while :; do
    case "$1" in
    --help)
        usage
        exit 0
        ;;
    --region)
        check-option-value "$1" "$2"
        REGION="$2"
        shift 2
        ;;
    --cluster)
        check-option-value "$1" "$2"
        ECS_CLUSTER="$2"
        shift 2
        ;;
    --activation-code)
        check-option-value "$1" "$2"
        ACTIVATION_CODE="$2"
        shift 2
        ;;
    --activation-id)
        check-option-value "$1" "$2"
        ACTIVATION_ID="$2"
        shift 2
        ;;
    --docker-install-source)
        check-option-value "$1" "$2"
        DOCKER_SOURCE="$2"
        shift 2
        ;;
    --ecs-version)
        check-option-value "$1" "$2"
        ECS_VERSION="$2"
        shift 2
        ;;
    --deb-url)
        check-option-value "$1" "$2"
        DEB_URL="$2"
        shift 2
        ;;
    --rpm-url)
        check-option-value "$1" "$2"
        RPM_URL="$2"
        shift 2
        ;;
    --ecs-endpoint)
        check-option-value "$1" "$2"
        ECS_ENDPOINT="$2"
        shift 2
        ;;
    --certs-file)
        check-option-value "$1" "$2"
        CERTS_FILE="$2"
        shift 2
        ;;
    --skip-registration)
        SKIP_REGISTRATION=true
        shift 1
        ;;
    --enable-gpu)
        GPU_ENABLED=true
        shift 1
        ;;
    --no-start)
        NO_START=true
        shift 1
        ;;
    --skip-gpg-check)
        CHECK_SIG=false
        shift 1
        ;;
    *)
        [ -z "$1" ] && break
        echo "invalid option: [$1]"
        fail
        ;;
    esac
done

# check if the script is run with root or sudo
if [ $(id -u) -ne 0 ]; then
    echo "Please run as root."
    fail
fi

# check if system is using systemd
# from https://www.freedesktop.org/software/systemd/man/sd_booted.html
if [ ! -d /run/systemd/system ]; then
    echo "The install script currently supports only systemd."
    fail
fi

SSM_SERVICE_NAME="amazon-ssm-agent"
SSM_BIN_NAME="amazon-ssm-agent"
if systemctl is-enabled snap.amazon-ssm-agent.amazon-ssm-agent.service &>/dev/null; then
    echo "Detected SSM agent installed via snap."
    SSM_SERVICE_NAME="snap.amazon-ssm-agent.amazon-ssm-agent.service"
    SSM_BIN_NAME="/snap/amazon-ssm-agent/current/amazon-ssm-agent"
fi
SSM_MANAGED_INSTANCE_ID=""

if [ -z "$REGION" ]; then
    echo "--region is required"
    fail
fi
# If activation code is absent and skip activation flag is present, set flag to skip ssm registration
# if both activation code is present
if $SKIP_REGISTRATION; then
    echo "Skipping ssm registration."
    if ! systemctl is-enabled $SSM_SERVICE_NAME &>/dev/null; then
        echo "--skip-registration flag specified but the SSM agent service is not running."
        echo "a running SSM agent service is required for ECS Anywhere."
        fail
    fi
else
    if [[ -z $ACTIVATION_ID || -z $ACTIVATION_CODE ]]; then
        echo "Both --activation-id and --activation-code are required unless --skip-registration is specified."
        fail
    fi
fi
if [ -z "$ECS_CLUSTER" ]; then
    ECS_CLUSTER="default"
fi
if [ -z "$DOCKER_SOURCE" ]; then
    DOCKER_SOURCE="all"
fi
if [ -z "$ECS_VERSION" ]; then
    ECS_VERSION="latest"
fi

ARCH=$(uname -m)
if [ "$ARCH" == "x86_64" ]; then
    ARCH_ALT="amd64"
elif [ "$ARCH" == "aarch64" ]; then
    ARCH_ALT="arm64"
else
    echo "Unsupported architecture: $ARCH"
    fail
fi

S3_BUCKET="amazon-ecs-agent-$REGION"
RPM_PKG_NAME="amazon-ecs-init-$ECS_VERSION.$ARCH.rpm"
DEB_PKG_NAME="amazon-ecs-init-$ECS_VERSION.$ARCH_ALT.deb"
S3_URL_SUFFIX=""
if grep -q "^cn-" <<< "$REGION"; then
    S3_URL_SUFFIX=".cn"
fi
S3_URL="https://s3.${REGION}.amazonaws.com${S3_URL_SUFFIX}"
SSM_S3_BUCKET="amazon-ssm-$REGION"

if [ -z "$RPM_URL" ]; then
    RPM_URL="${S3_URL}/${S3_BUCKET}/$RPM_PKG_NAME"
fi
if [ -z "$DEB_URL" ]; then
    DEB_URL="${S3_URL}/${S3_BUCKET}/$DEB_PKG_NAME"
fi

# source /etc/os-release to get the VERSION_ID and ID fields
source /etc/os-release
echo "Running ECS install script on $ID $VERSION_ID"
echo "###"
echo ""
DISTRO=""
if echo "$ID" | grep ubuntu; then
    DISTRO="ubuntu"
elif echo "$ID" | grep debian; then
    DISTRO="debian"
elif echo "$ID" | grep fedora; then
    DISTRO="fedora"
elif echo "$ID" | grep centos; then
    DISTRO="centos"
elif echo "$ID" | grep rhel; then
    DISTRO="rhel"
elif [[ "$ID" == "amzn" && "$VERSION_ID" == "2" ]]; then
    DISTRO="al2"
fi

if [ "$DISTRO" == "rhel" ]; then
    if [ ! "$DOCKER_SOURCE" == "none" ]; then
        echo "Docker install is not supported on RHEL. Please install yourself and rerun with --docker-install-source none"
        fail
    fi
fi

ok() {
    echo ""
    echo "# ok"
    echo "##########################"
    echo ""
}

try() {
    local action=$*
    echo ""
    echo "##########################"
    echo "# Trying to $action ... "
    echo ""
}

PKG_MANAGER=""
if [ -x "$(command -v dnf)" ]; then
    PKG_MANAGER="dnf"
    dnf install -y jq
elif [ -x "$(command -v yum)" ]; then
    PKG_MANAGER="yum"
    if [ "$DISTRO" != "al2" ]; then
        yum install epel-release -y
    fi
    yum install -y jq
elif [ -x "$(command -v apt)" ]; then
    PKG_MANAGER="apt"
    try "Update apt repos"
    apt update -y
    apt-get install -y curl jq
    ok
elif [ -x "$(command -v zypper)" ]; then
    PKG_MANAGER="zypper"
    zypper install -y jq
else
    echo "Unsupported package manager. Could not find dnf, yum, or apt."
    fail
fi

get-ssm-managed-instance-id() {
    SSM_REGISTRATION_FILE='/var/lib/amazon/ssm/Vault/Store/RegistrationKey'
    if [ -f ${SSM_REGISTRATION_FILE} ]; then
        SSM_MANAGED_INSTANCE_ID=$(jq -r ".instanceID" $SSM_REGISTRATION_FILE)
    fi
}

curl-helper() {
    if ! curl -o "$1" "$2" -fSs; then
        echo "Failed to download $2"
        fail
    fi
}

register-ssm-agent() {
    try "Register SSM agent"
    get-ssm-managed-instance-id
    if [ -z "$SSM_MANAGED_INSTANCE_ID" ]; then
        systemctl stop "$SSM_SERVICE_NAME" &>/dev/null
        $SSM_BIN_NAME -register -code "$ACTIVATION_CODE" -id "$ACTIVATION_ID" -region "$REGION"
        systemctl enable "$SSM_SERVICE_NAME"
        if ! $NO_START; then
            systemctl start "$SSM_SERVICE_NAME"
        else
            echo "Skip starting ssm agent because --no-start is specified."
        fi
        echo "SSM agent has been registered."
    else
        echo "SSM agent is already registered. Managed instance ID: $SSM_MANAGED_INSTANCE_ID"
    fi
    ok
}

install-ssm-agent() {
    try "install ssm agent"
    if systemctl is-enabled $SSM_SERVICE_NAME &>/dev/null; then
        echo "SSM agent is already installed."
    else
        local dir
        dir="$(mktemp -d)"
        local SSM_DEB_URL="${S3_URL}/${SSM_S3_BUCKET}/latest/debian_$ARCH_ALT/amazon-ssm-agent.deb"
        local SSM_RPM_URL="${S3_URL}/${SSM_S3_BUCKET}/latest/linux_$ARCH_ALT/amazon-ssm-agent.rpm"
        local SSM_DEB_PKG_NAME="ssm-agent.deb"
        local SSM_RPM_PKG_NAME="ssm-agent.rpm"

        case "$PKG_MANAGER" in
        apt)
            curl-helper "$dir/$SSM_DEB_PKG_NAME" "$SSM_DEB_URL"
            curl-helper "$dir/$SSM_DEB_PKG_NAME.sig" "$SSM_DEB_URL.sig"
            ssm-agent-signature-verify "$dir/$SSM_DEB_PKG_NAME.sig" "$dir/$SSM_DEB_PKG_NAME"
            chmod -R a+rX "$dir"
            dpkg -i "$dir/ssm-agent.deb"
            ;;
        dnf | yum | zypper)
            curl-helper "$dir/$SSM_RPM_PKG_NAME" "$SSM_RPM_URL"
            curl-helper "$dir/$SSM_RPM_PKG_NAME.sig" "$SSM_RPM_URL.sig"
            ssm-agent-signature-verify "$dir/$SSM_RPM_PKG_NAME.sig" "$dir/$SSM_RPM_PKG_NAME"
            local args=""
            local install_args="-y"
            if [[ "$PKG_MANAGER" == "zypper" ]]; then
                install_args="${install_args} --allow-unsigned-rpm"
                args="--no-gpg-checks"
            fi
            $PKG_MANAGER ${args} install ${install_args} "$dir/$SSM_RPM_PKG_NAME"
            ;;
        esac
        rm -rf "$dir"
    fi
    # register the instance
    register-ssm-agent
    ok
}

ssm-agent-signature-verify() {
    try "verify the signature of amazon-ssm-agent package"
    if ! command -v gpg; then
        echo "WARNING: gpg command not available on this server, not able to verify amazon-ssm-agent package signature."
        ok
        return
    fi

    curl-helper "$dir/amazon-ssm-agent.gpg" "https://raw.githubusercontent.com/aws/amazon-ecs-init/master/scripts/amazon-ssm-agent.gpg"
    gpg --import "$dir/amazon-ssm-agent.gpg"

    if gpg --verify "$1" "$2"; then
        echo "amazon-ssm-agent GPG verification passed. Install the amazon-ssm-agent."
    else
        echo "amazon-ssm-agent GPG verification failed. Stop the installation of the amazon-ssm-agent. Please contact AWS Support."
        fail
    fi

    ok
}

# order of operations:
# all->docker->distro->none
install-docker() {
    if [ -x "$(command -v docker)" ]; then
        echo "docker is already installed, skipping installation"
        return
    fi

    case "$1" in
    all)
        install-docker "docker"
        return
        ;;
    docker)
        try "install docker from docker repos"
        case "$DISTRO" in
        centos)
            # TODO use dnf on centos if available
            yum install -y yum-utils
            yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
            yum install -y docker-ce docker-ce-cli containerd.io
            ;;
        fedora)
            dnf install -y dnf-plugins-core
            dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
            dnf install -y docker-ce docker-ce-cli containerd.io
            ;;
        debian)
            apt install -y apt-transport-https ca-certificates gnupg-agent software-properties-common
            curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
            add-apt-repository \
                "deb [arch=$ARCH_ALT] https://download.docker.com/linux/debian \
              $(lsb_release -cs) \
              stable"
            apt update -y
            apt install -y docker-ce docker-ce-cli containerd.io
            ;;
        ubuntu)
            apt install -y apt-transport-https ca-certificates gnupg-agent software-properties-common
            curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
            add-apt-repository \
                "deb [arch=$ARCH_ALT] https://download.docker.com/linux/ubuntu \
              $(lsb_release -cs) \
              stable"
            apt update -y
            apt install -y docker-ce docker-ce-cli containerd.io
            ;;
        *)
            echo "Docker install repos not supported for this distro, trying distro install"
            install-docker "distro"
            return
            ;;
        esac
        ;;
    distro)
        try "install docker from distribution repos"

        # centos and fedora enable selinux by default in their distro installs
        case "$DISTRO" in
        centos | fedora)
            if [ "$VERSION_ID" == "8" ]; then
                echo "--docker-install-source distro is not supported on centos 8 because docker package is not available."
            else
                echo "--docker-install-source distro is not supported on $DISTRO $VERSION_ID because distro enables selinux by default."
            fi
            echo "We suggest installing using '--docker-install-source docker' or installing docker yourself before running this script."
            fail
            ;;
        esac

        case "$PKG_MANAGER" in
        dnf)
            dnf install -y docker
            ;;
        yum)
            yum install -y docker
            ;;
        apt)
            apt install -y docker.io
            ;;
        zypper)
            zypper install -y docker
            ;;
        esac
        ;;
    none)
        echo "Docker install source is none, not installing docker"
        ;;
    esac

    ok
}

install-ecs-agent() {
    try "install ecs agent"
    if [ -x "/usr/libexec/amazon-ecs-init" ]; then
        echo "ecs agent is already installed"
        ok
        return
    fi

    local dir
    dir="$(mktemp -d)"
    case "$PKG_MANAGER" in
    apt)
        curl-helper "$dir/$DEB_PKG_NAME" "$DEB_URL"
        if $CHECK_SIG; then
            curl-helper "$dir/$DEB_PKG_NAME.asc" "$DEB_URL.asc"
            ecs-init-signature-verify "$dir/$DEB_PKG_NAME.asc" "$dir/$DEB_PKG_NAME"
        fi
        chmod -R a+rX "$dir"
        apt install -y "$dir/$DEB_PKG_NAME"
        rm -rf "$dir"
        ;;
    dnf | yum | zypper)
        curl-helper "$dir/$RPM_PKG_NAME" "$RPM_URL"
        if $CHECK_SIG; then
            curl-helper "$dir/$RPM_PKG_NAME.asc" "$RPM_URL.asc"
            ecs-init-signature-verify "$dir/$RPM_PKG_NAME.asc" "$dir/$RPM_PKG_NAME"
        fi
        local args="-y"
        if [[ "$PKG_MANAGER" == "zypper" ]]; then
            args="${args} --allow-unsigned-rpm"
        fi
        $PKG_MANAGER install ${args} "$dir/$RPM_PKG_NAME"
        rm -rf "$dir"
        ;;
    esac

    if [ ! -f "/etc/ecs/ecs.config" ]; then
        touch /etc/ecs/ecs.config
    else
        echo "/etc/ecs/ecs.config already exists, preserving existing config and appending cluster name."
    fi
    echo "ECS_CLUSTER=$ECS_CLUSTER" >>/etc/ecs/ecs.config

    if [ ! -f "/var/lib/ecs/ecs.config" ]; then
        touch /var/lib/ecs/ecs.config
    else
        echo "/var/lib/ecs/ecs.config already exists, preserving existing config and appending ECS anywhere requirements."
    fi
    echo "AWS_DEFAULT_REGION=$REGION" >>/var/lib/ecs/ecs.config
    echo "ECS_EXTERNAL=true" >>/var/lib/ecs/ecs.config
    if [ -n "$ECS_ENDPOINT" ]; then
        echo "ECS_BACKEND_HOST=$ECS_ENDPOINT" >>/var/lib/ecs/ecs.config
    fi
    if [ -n "$GPU_ENABLED" ]; then
        if ! nvidia-smi &>/dev/null; then
            echo "Failed to detect GPU with nvidia-smi command. Make sure that GPUs are attached and the latest NVIDIA driver is installed and running."
            fail
        fi
        echo "ECS_ENABLE_GPU_SUPPORT=true" >>/var/lib/ecs/ecs.config
    fi
    systemctl enable ecs
    if ! $NO_START; then
        systemctl start ecs
    else
        echo "Skip starting ecs agent because --no-start is specified."
    fi

    ok
}

ecs-init-signature-verify() {
    try "verify the signature of amazon-ecs-init package"
    if ! command -v gpg; then
        echo "WARNING: gpg command not available on this server, not able to verify amazon-ecs-init package signature."
        ok
        return
    fi

    curl-helper "$dir/amazon-ecs-agent.gpg" "https://raw.githubusercontent.com/aws/amazon-ecs-init/master/scripts/amazon-ecs-agent.gpg"
    gpg --import "$dir/amazon-ecs-agent.gpg"
    if gpg --verify "$1" "$2"; then
        echo "amazon-ecs-init GPG verification passed. Install amazon-ecs-init."
    else
        echo "amazon-ecs-init GPG verification failed. Stop the installation of amazon-ecs-init. Please contact AWS Support."
        fail
    fi

    ok
}

wait-agent-start() {
    if $NO_START; then
        echo "--no-start is specified. Not verifying ecs agent startup."
        return
    fi
    try "wait for ECS agent to start"

    retryLimit=10
    i=0
    for ((i = 0 ; i < retryLimit ; i++))
    do
        curlResult="$(timeout 10 curl -s http://localhost:51678/v1/metadata | jq .ContainerInstanceArn)"
        if [ ! "$curlResult" == "null" ] && [ -n "$curlResult" ]; then
            echo "Ping ECS Agent registered successfully! Container instance arn: $curlResult"
            echo ""
            echo "You can check your ECS cluster here https://console.aws.amazon.com/ecs/home?region=$REGION#/clusters/$ECS_CLUSTER"
            ok
            return
        fi
        sleep 10 # wait for 10s before next retry for agent to start up.
    done

    # TODO Update to ecs anywhere specific documentation when available.
    echo "Timed out waiting for ECS Agent to start. Please check logs at /var/log/ecs/ecs-agent.log and follow troubleshooting documentation at https://docs.aws.amazon.com/AmazonECS/latest/developerguide/troubleshooting.html"
    fail
}

exec-setup() {
    find-copy-certs-exec
    download-ssm-binaries-exec
}

find-copy-certs-exec() {
    # Reference for locations: https://golang.org/src/crypto/x509/root_linux.go
    CERTS_FILES_LOCATIONS=("/etc/ssl/certs/ca-certificates.crt"
      "/etc/pki/tls/certs/ca-bundle.crt"
      "/etc/ssl/ca-bundle.pem"
      "/etc/pki/tls/cacert.pem"
      "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem"
      "/etc/ssl/cert.pem"
    )
    CERTS_PATH="/var/lib/ecs/deps/execute-command/certs"

    echo "Copying certs for exec feature"

    # Determine certs file
    certs=""
    if [ -n "$CERTS_FILE" ] && [ -f "$CERTS_FILE" ]; then
        certs=$CERTS_FILE
    else
        if [ -n "$CERTS_FILE" ]; then
            echo "Provided certs file does not exist, looking for certs in known possible locations"
        fi
        for f in "${CERTS_FILES_LOCATIONS[@]}"
        do
            if  [ -f "$f" ]; then
                certs=$f
                break
            fi
        done
    fi

    # Copy certs to exec directory
    if [ -z "$certs" ]; then
        echo "Could not find certificates. Please rerun with --certs-file and provide a valid path"
        fail
    else
        echo "Using $certs"
        openssl verify -x509_strict "$certs"
        mkdir -p $CERTS_PATH
        cp "$certs" $CERTS_PATH/tls-ca-bundle.pem
        chmod 400 $CERTS_PATH/tls-ca-bundle.pem
    fi
    ok
}

download-ssm-binaries-exec() {
    BINARY_VERSION="3.1.804.0"
    BINARY_PATH="/var/lib/ecs/deps/execute-command/bin/${BINARY_VERSION}"
    BINARY_DOWNLOAD_PATH="ssm-binaries"

    # Download SSM binaries from S3
    echo "Downloading SSM binaries for exec feature"

    mkdir -p $BINARY_DOWNLOAD_PATH
    curl "${S3_URL}/${SSM_S3_BUCKET}/${BINARY_VERSION}/linux_$ARCH_ALT/amazon-ssm-agent-binaries.tar.gz" -o ${BINARY_DOWNLOAD_PATH}/amazon-ssm-agent.tar.gz
    tar -xvf ${BINARY_DOWNLOAD_PATH}/amazon-ssm-agent.tar.gz -C ${BINARY_DOWNLOAD_PATH}/

    # Copy binaries to exec directory
    mkdir -p ${BINARY_PATH}
    cp ${BINARY_DOWNLOAD_PATH}/amazon-ssm-agent ${BINARY_PATH}/amazon-ssm-agent
    cp ${BINARY_DOWNLOAD_PATH}/ssm-agent-worker ${BINARY_PATH}/ssm-agent-worker
    cp ${BINARY_DOWNLOAD_PATH}/ssm-session-worker ${BINARY_PATH}/ssm-session-worker
    rm -rf ${BINARY_DOWNLOAD_PATH}
    ok
}

show-license() {
    echo ""
    echo "##########################"
    echo "This script installed three open source packages that all use Apache License 2.0."
    echo "You can view their license information here:"
    echo "  - ECS Agent https://github.com/aws/amazon-ecs-agent/blob/master/LICENSE"
    echo "  - SSM Agent https://github.com/aws/amazon-ssm-agent/blob/master/LICENSE"
    echo "  - Docker engine https://github.com/moby/moby/blob/master/LICENSE"
    echo "##########################"
    echo ""
}

if ! $SKIP_REGISTRATION; then
    install-ssm-agent
fi
install-docker "$DOCKER_SOURCE"
exec-setup
install-ecs-agent
wait-agent-start
show-license


#!/bin/bash
# Copyright 2014-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the
# "License"). You may not use this file except in compliance
#  with the License. A copy of the License is located at
#
#     http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and
# limitations under the License.
set -x
set -e
export TOPWD="$(pwd)"
export BUILDDIR="$(mktemp -d)"
export GOPATH="${TOPWD}/ecs-init/:${BUILDDIR}"
export SRCPATH="${BUILDDIR}/src/github.com/aws/amazon-ecs-init"
export GO111MODULE="auto"

if [ -d "${TOPWD}/.git" ]; then
    version=$(cat "${TOPWD}/ecs-init/ECSVERSION")
    git_hash=$(git rev-parse --short=8 HEAD)
    git_dirty=false

    if [[ "$(git status --porcelain)" != "" ]]; then
	git_dirty=true
    fi

    VERSION_FLAG="-X github.com/aws/amazon-ecs-init/ecs-init/version.Version=${version}"
    GIT_HASH_FLAG="-X github.com/aws/amazon-ecs-init/ecs-init/version.GitShortHash=${git_hash}"
    GIT_DIRTY_FLAG="-X github.com/aws/amazon-ecs-init/ecs-init/version.GitDirty=${git_dirty}"
fi

mkdir -p "${SRCPATH}"
ln -s "${TOPWD}/ecs-init" "${SRCPATH}"
cd "${SRCPATH}/ecs-init"
if [[ "$1" == "dev" ]]; then
	CGO_ENABLED=1 CGO_LDFLAGS_ALLOW='-Wl,--unresolved-symbols=ignore-in-object-files' go build -tags 'development' -ldflags "${VERSION_FLAG} ${GIT_HASH_FLAG} ${GIT_DIRTY_FLAG}" \
	   -o "${TOPWD}/amazon-ecs-init"
else
	tags=""
	if [[ "$1" != "" ]]; then
		tags="-tags '$1'"
	fi
	CGO_ENABLED=1 CGO_LDFLAGS_ALLOW='-Wl,--unresolved-symbols=ignore-in-object-files' go build -a ${tags} -x \
		   -ldflags "-s ${VERSION_FLAG} ${GIT_HASH_FLAG} ${GIT_DIRTY_FLAG}" \
		   -o "${TOPWD}/amazon-ecs-init"
fi
CGO_ENABLED=0 go build -x -ldflags "-s ${VERSION_FLAG} ${GIT_HASH_FLAG} ${GIT_DIRTY_FLAG}" \
	-o "${TOPWD}/amazon-ecs-volume-plugin" "./volumes/amazon-ecs-volume-plugin"
rm -r "${BUILDDIR}"


#!/bin/sh
# Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the
# "License"). You may not use this file except in compliance
#  with the License. A copy of the License is located at
#
#     http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and
# limitations under the License.

if [ -z "$1" ] || [ ! -z $(echo "$1" | tr -d "[:digit:]") ]; then
	echo "Must provide numeric argument"
	exit 1
fi

exit_code="$1"

die() {
	exit $exit_code
}

start_wait() {
	echo "Waiting for SIGTERM or SIGINT to exit"
	while true
	do
		sleep 1 &
		wait ${!}
	done
}

SIGINT=2
SIGTERM=15
trap die $SIGINT $SIGTERM
start_wait


#!/bin/bash
# Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the
# "License"). You may not use this file except in compliance
#  with the License. A copy of the License is located at
#
#     http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and
# limitations under the License.
#
# This script wraps the mockgen tool and inserts licensing information.
# Usage: mockgen.sh target-package-name source-file-name [relative-output-directory-path]

package="$1"
inputfile="$2"
outputfile="$(echo ${inputfile} | sed -e 's/\.go$/_mocks.go/')"
relativeoutputdir="$3"

echo "Generating mocks from ${inputfile} to ${outputfile} in package ${package}"

export PATH="${GOPATH//://bin:}/bin:$PATH"

tmp_gen="$(mktemp)"
year="$(date +"%Y")"
mockgen -source "$(pwd)/${inputfile}" -package "${package}" | goimports > "${tmp_gen}"
cat  > "$(pwd)/${relativeoutputdir}/${outputfile}" << EOF
// Copyright 2015-${year} Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
//     http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.
//
// Source: $(basename ${inputfile}) in package ${package}
$(grep -v "// Source: .*${inputfile}" ${tmp_gen})
EOF
rm "${tmp_gen}"


#!/bin/bash

# Copyright 2014-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You may not
# use this file except in compliance with the License. A copy of the License
# is located at
#
#     http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is distributed
# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied. See the License for the specific language governing
# permissions and limitations under the License.

# This script will update the information of the ecs-init during building
set -e -x

CURRENTDIR=$(dirname "${0}")
version=$(cat "${CURRENTDIR}"/../ecs-init/ECSVERSION)
git_hash=$(git rev-parse --short=8 HEAD)
git_dirty=false

if [[ "$(git status --porcelain)" != "" ]]; then
	git_dirty=true
fi

cat << EOF > "${CURRENTDIR}"/../ecs-init/version/version.go
// This is an autogenerated file and should not be edited.

// Copyright 2014-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
//	http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.

// Package version contains constants to indicate the current version of the
// ecs-init. It is autogenerated.
package version

// Version is the version of the ecs-init
var Version string = "${version}"

// GitDirty indicates the cleanliness of the git repo when this ecs-init was built
var GitDirty string = "${git_dirty}"

// GitShortHash is the short hash of this ecs-init build
var GitShortHash string = "${git_hash}"
EOF


#!/usr/bin/env bash
#
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License").
# You may not use this file except in compliance with the License.
# A copy of the License is located at
#
#    http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file.
# This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
#
#
# - Collects Docker daemon and Amazon ECS Container Agent logs on Amazon Linux,
#   Redhat 7, Debian 8.
# - Collects general operating system logs.
# - Optional ability to enable debug mode for the Docker daemon and Amazon ECS
#   Container Agent on Amazon Linux variants, such as the Amazon ECS-optimized
#   AMI. For usage information, see --help.

export LANG="C"
export LC_ALL="C"

# Collection configuration

# curdir is the working root of collection.
curdir="$(dirname "$0")"
# collectdir is where all collected informaton is placed under. This
# services as the top level for this script's operation.
readonly collectdir="${curdir}/collect"

# datetime is the date and time when the script was executed used in pack()
datetime=`date +%Y%m%d%H%M`

# pack_name is the name of the resulting tarball. This will generally
# be collect-i-ffffffffffffffffff-YYYYMMDDHHmm, where i-ffffffffffffffffff is the
# instance id and YYYYMMDDHHmm is date and time.
pack_name="collect"

# Shared check variables

# info_system is where the checks' data is placed.
info_system="${collectdir}/system"
# pkgtype is the detected packaging system used on the host (eg: yum, deb)
pkgtype=''  # defined in get_pkgtype
# jsonformatter is the detected tool to process JSON installed on the host
jsonformatter=''
# init_type is the operating system type used for casing check behavior.
init_type=''  # defined in get_init_type
progname='' # defined in parse_options
# dstdir is the destination where the logs collected are placed.
dstdir=''  # defined in several routines

# Script run defaults

mode='brief' # defined in parse_options

# Common functions
# ---------------------------------------------------------------------------------------

help() {
  echo "USAGE: ${progname} [--mode=[brief|enable-debug]]"
  echo "       ${progname} --help"
  echo ""
  echo "OPTIONS:"
  echo "     --mode  Sets the desired mode of the script. For more information,"
  echo "             see the MODES section."
  echo "     --help  Show this help message."
  echo ""
  echo "MODES:"
  echo "     brief         Gathers basic operating system, Docker daemon, and Amazon"
  echo "                   ECS Container Agent logs. This is the default mode."
  echo "     enable-debug  Enables debug mode for the Docker daemon and the Amazon"
  echo "                   ECS Container Agent. Only supported on Systemd init systems"
  echo "                   and Amazon Linux."
}

parse_options() {
  local count="$#"

  progname="$0"

  for i in $(seq "$count"); do
    eval arg=\$"$i"
    # shellcheck disable=SC2154
    param="$(echo "$arg" | awk -F '=' '{print $1}' | sed -e 's|--||')"
    val="$(echo "$arg" | awk -F '=' '{print $2}')"

    case "${param}" in
      mode)
        eval "$param"="${val}"
        ;;
      help)
        help && exit 0
        ;;
      *)
        echo "Parameter not found: '$param'"
        help && exit 1
        ;;
    esac
  done
}

ok() {
  echo "ok"
}

info() {
  echo "$*"
}

try() {
  local action=$*
  echo -n "Trying to $action ... "
}

warning() {
  local reason=$*
  echo "warning: $reason"
}

failed() {
  local reason=$*
  echo "failed: $reason"
}

die() {
  echo "ERROR: $*"
  exit 1
}

is_root() {
  try "check if the script is running as root"

  if [[ "$(id -u)" != "0" ]]; then
    die "this script must be run as root!"

  fi

  ok
}

cleanup() {
  rm -rf "$collectdir" >/dev/null 2>&1
  rm -f "$curdir"/collect.tgz
}

init() {
  is_root
  try_set_instance_collectdir
  get_init_type
  get_pkgtype
  get_jsonformatter
}

collect_brief() {
  init
  is_diskfull
  get_common_logs
  get_kernel_logs
  get_mounts_info
  get_selinux_info
  get_iptables_info
  get_pkglist
  get_system_services
  get_docker_info
  get_docker_containers_info
  get_docker_logs
  get_docker_systemd_config
  get_docker_sysconfig
  get_docker_daemon_json
  get_ecs_agent_logs
  get_ecs_agent_info
  get_open_files
  get_os_release
  get_uname_info
  get_dmidecode_info
  get_lsmod_info
  get_cgroupv2_events
  get_systemd_slice_info
  get_veth_info
  get_gpu_info
}

enable_debug() {
  is_root
  get_init_type
  enable_docker_debug
  enable_ecs_agent_debug
}

# Routines
# ---------------------------------------------------------------------------------------

# uname gets basic system and kernel information.
get_uname_info() {
  try "get uname kernel info"

  mkdir -p "$info_system"
  uname -a > "$info_system"/uname.txt

  ok
}

# dmidecode is a tool sometimes installed on VMs that provides detailed
# information about the VM hypervisor, underlying hardware, and system.
get_dmidecode_info() {
  try "get dmidecode info"

  if command -v dmidecode &>/dev/null; then
    mkdir -p "$info_system"
    dmidecode > "$info_system"/dmidecode.txt
  fi

  ok
}

# lsmod lists loadable kernel modules.
get_lsmod_info() {
  try "get lsmod info"

  if command -v lsmod &>/dev/null; then
    mkdir -p "$info_system"
    lsmod > "$info_system"/lsmod.txt
  fi

  ok
}

get_init_type() {
  try "collect system information"

  case "$(cat /proc/1/comm)" in
    systemd)
      init_type="systemd"
    ;;
    *)
      init_type="other"
    ;;
  esac

  ok
}

get_pkgtype() {
  if [[ -n "$(command -v rpm)" ]]; then
    pkgtype="rpm"
  elif [[ -n "$(command -v dpkg)" ]]; then
    pkgtype="dpkg"
  else
    pkgtype="unknown"
  fi
}

get_jsonformatter(){
  if [[ -n "$(command -v python)" ]]; then
    jsonformatter="python -mjson.tool"
  elif [[ -n "$(command -v jq)" ]]; then
    jsonformatter="jq"
  else
    jsonformatter=""
  fi
}

try_set_instance_collectdir() {
  try "resolve instance-id"

  if [ -f /var/lib/amazon/ssm/registration ]; then
    info "SSM managed instance detected, getting managed instance id"
    if command -v jq > /dev/null; then
      instance_id=$(jq -r ".ManagedInstanceID" < /var/lib/amazon/ssm/registration)
    fi
  fi

  if test -z "$instance_id" && command -v curl > /dev/null; then
    info "getting instance id from ec2 metadata endpoint"
    imds="http://169.254.169.254/latest"
    token=$(curl -sS --retry 3 -X PUT "${imds}/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" 2>/dev/null)
    instance_id=$(curl -sS --retry 3 -H "X-aws-ec2-metadata-token: $token" "${imds}/meta-data/instance-id" 2>/dev/null)
  fi

  if [ -n "$instance_id" ]; then
    # Put logs into a directory for this instance.
    info_system="${collectdir}/${instance_id}"
    # And in a pack that includes the instance id in its name.
    pack_name="collect-${instance_id}"
    mkdir -p "${info_system}"
    echo "$instance_id" > "$info_system"/instance-id.txt
  else
    warning "unable to get instance id"
    return 1
  fi

  ok
}

pack() {
  try "archive gathered log information"

  local tar_bin
  tar_bin="$(command -v tar 2>/dev/null)"
  [ -z "${tar_bin}" ] && warning "TAR archiver not found, please install a TAR archiver to create the collection archive. You can still view the logs in the collect folder."

  cd "$curdir" || { echo "cd failed."; exit 1; }

  ${tar_bin} -cvzf "$curdir/$pack_name-$datetime".tgz "$collectdir" > /dev/null 2>&1

  ok
}

is_diskfull() {
  try "check disk space usage"

  threshold=70
  i=2
  result=$(df -kh | grep -ve "Filesystem" -ve "loop" | awk '{ print $5 }' | sed 's/%//g')
  exceeded=0

  for percent in ${result}; do
    if [[ "${percent}" -gt "${threshold}" ]]; then
      partition=$(df -kh | head -$i | tail -1| awk '{print $1}')
      echo
      warning "${partition} is ${percent}% full, please ensure adequate disk space to collect and store the log files."
      : $((exceeded++))
    fi
    i=$((i+1))
  done

  if [ "$exceeded" -gt 0 ]; then
    return 1
  else
    ok
  fi
}

get_mounts_info() {
  try "get mount points and volume information"

  mkdir -p "$info_system"
  mount > "$info_system"/mounts.txt
  echo "" >> "$info_system"/mounts.txt
  df -h >> "$info_system"/mounts.txt

  if command -v lvdisplay > /dev/null; then
    lvdisplay > "$info_system"/lvdisplay.txt
    vgdisplay > "$info_system"/vgdisplay.txt
    pvdisplay > "$info_system"/pvdisplay.txt
  fi

  ok
}

get_veth_info() {
  try "get veth info"

  if command -v brctl >/dev/null; then
    brctl show > "$info_system"/brctlshow.txt
  fi

  if command -v ip >/dev/null; then
    ip addr show > "$info_system"/ipaddrshow.txt
  fi

  ok
}

get_selinux_info() {
  try "check SELinux status"

  enforced="$(getenforce 2>/dev/null)"

  { [ "${pkgtype}" != "rpm" ] || [ -z "${enforced}" ]; } \
    && info "not installed" \
    && return

  mkdir -p "$info_system"
  echo -e "SELinux mode:\\n    ${enforced}" >  "$info_system"/selinux.txt

  ok
}

get_iptables_info() {
  try "get iptables list"

  mkdir -p "$info_system"
  iptables -nvL -t filter > "$info_system"/iptables-filter.txt
  iptables -nvL -t nat  > "$info_system"/iptables-nat.txt

  ok
}

get_open_files() {
  try "get open files list"

  mkdir -p "$info_system"
  for d in /proc/*/fd; do echo "$d"; find "$d" -maxdepth 1 | wc -l; done > "$info_system"/open-file-counts.txt
  ls -l /proc/*/fd > "$info_system"/open-file-details.txt

  ok
}

get_common_logs() {
  try "collect common operating system logs"

  mkdir -p "$info_system"
  if command -v journalctl >/dev/null; then
      journalctl > "${info_system}"/system.log
  fi

  dstdir="${info_system}/var_log"
  mkdir -p "$dstdir"

  for entry in syslog messages; do
    [ -e "/var/log/${entry}" ] && cp -f /var/log/${entry} "$dstdir"/
  done

  ok
}

get_kernel_logs() {
  try "collect kernel logs"

  dstdir="${info_system}/kernel"
  mkdir -p "$dstdir"
  if [ -e "/var/log/dmesg" ]; then
    cp -f /var/log/dmesg "$dstdir/dmesg.boot"
  fi
  dmesg > "$dstdir/dmesg.current"
  dmesg --ctime > "$dstdir/dmesg.human.current"
  ok
}

get_docker_logs() {
  try "collect Docker and containerd daemon logs"

  dstdir="${info_system}/docker_log"
  mkdir -p "$dstdir"
  case "${init_type}" in
    systemd)
      journalctl -u docker > "${dstdir}"/docker
      journalctl -u containerd > "${info_system}"/containerd.log
      ;;
    other)
      for entry in docker upstart/docker; do
        if [[ -e "/var/log/${entry}" ]]; then
          cp -f /var/log/"${entry}" "${dstdir}"/docker
        fi
      done
      ;;
    *)
      warning "the current operating system is not supported."
      return 1
      ;;
  esac

  ok
}

get_ecs_agent_logs() {
  try "collect Amazon ECS Container Agent logs"

  dstdir="${info_system}/ecs_agent_logs"

  if [ ! -d /var/log/ecs ]; then
    failed "ECS log directory does not exist"
    return 1
  fi

  mkdir -p "$dstdir"

  cp -f -r /var/log/ecs/* "$dstdir"/

  ok
}

get_pkglist() {
  try "detect installed packages"

  mkdir -p "$info_system"
  case "${pkgtype}" in
    rpm)
      rpm -qa >"$info_system"/pkglist.txt 2>&1
      ;;
    dpkg)
      dpkg --list > "$info_system"/pkglist.txt 2>&1
      ;;
    *)
      warning "unknown package type."
      return 1
      ;;
  esac

  ok
}

get_system_services() {
  try "detect active system services list"

  mkdir -p "$info_system"
  case "${init_type}" in
    systemd)
      systemctl list-units > "$info_system"/services.txt 2>&1
      ;;
    other)
      service --status-all >> "$info_system"/services.txt 2>&1
      ;;
    *)
      warning "unable to determine active services."
      return 1
      ;;
  esac

  top -b -n 1 > "$info_system"/top.txt 2>&1
  ps fauxwww > "$info_system"/ps.txt 2>&1
  netstat -plant > "$info_system"/netstat.txt 2>&1

  ok
}

get_docker_info() {
  try "gather Docker daemon information"

  mkdir -p "$info_system"/docker

  if pgrep dockerd > /dev/null ; then

    timeout 20 docker info > "$info_system"/docker/docker-info.txt 2>&1 || echo "Timed out, ignoring \"docker info output \" "
    timeout 20 docker ps --all --no-trunc > "$info_system"/docker/docker-ps.txt 2>&1 || echo "Timed out, ignoring \"docker ps --all --no-trunc output \" "
    timeout 20 docker images > "$info_system"/docker/docker-images.txt 2>&1 || echo "Timed out, ignoring \"docker images output \" "
    timeout 20 docker version > "$info_system"/docker/docker-version.txt 2>&1 || echo "Timed out, ignoring \"docker version output \" "
    timeout 60 docker stats --all --no-trunc --no-stream > "$info_system"/docker/docker-stats.txt 2>&1 || echo "Timed out, ignoring \"docker stats\" output"

    ok
  else
    warning "the Docker daemon is not running." | tee "$info_system"/docker/docker-not-running.txt
  fi
}

get_ecs_agent_info() {
  try "collect Amazon ECS Container Agent state and config"

  mkdir -p "$info_system"/ecs-agent
  if [ -e /var/lib/ecs/data/ecs_agent_data.json ]; then
    cp -f /var/lib/ecs/data/ecs_agent_data.json "$info_system"/ecs-agent/ecs_agent_data.txt 2>&1
    if [ -n "$jsonformatter" ]; then
      cat "$info_system"/ecs-agent/ecs_agent_data.txt | $jsonformatter > "$info_system"/ecs-agent/ecs_agent_data_tmp.txt
      mv "$info_system"/ecs-agent/ecs_agent_data_tmp.txt "$info_system"/ecs-agent/ecs_agent_data.txt
    fi
  fi

  if [ -e /var/lib/ecs/data/agent.db ]; then
    cp -f /var/lib/ecs/data/agent.db "$info_system"/ecs-agent/agent.db 2>&1
    chmod +r "$info_system"/ecs-agent/agent.db
  fi

  if [ -e /etc/ecs/ecs.config ]; then
    cp -f /etc/ecs/ecs.config "$info_system"/ecs-agent/ 2>&1
    if grep --quiet "ECS_ENGINE_AUTH_DATA" "$info_system"/ecs-agent/ecs.config; then
      sed -i 's/ECS_ENGINE_AUTH_DATA=.*/ECS_ENGINE_AUTH_DATA=/g' "$info_system"/ecs-agent/ecs.config
    fi
  fi
  ok

  try "collect Amazon ECS Container Agent engine data"

  if pgrep agent > /dev/null ; then
    if command -v curl >/dev/null; then
      if curl --max-time 3 -s http://localhost:51678/v1/tasks > "$info_system"/ecs-agent/agent-running-info.txt 2>&1; then
        if [ -n "$jsonformatter" ]; then
          cat "$info_system"/ecs-agent/agent-running-info.txt | $jsonformatter > "$info_system"/ecs-agent/agent-running-info-tmp.txt
          mv "$info_system"/ecs-agent/agent-running-info-tmp.txt "$info_system"/ecs-agent/agent-running-info.txt
        fi
          ok
      else
          warning "failed to get agent data"
      fi
    else
      warning "curl is unavailable for probing ECS Container Agent introspection endpoint"
    fi
  else
    warning "The Amazon ECS Container Agent is not running" | tee "$info_system"/ecs-agent/ecs-agent-not-running.txt
    return 1
  fi
}

get_docker_containers_info() {
  try "inspect all Docker containers"

  mkdir -p "$info_system"/docker

  if pgrep dockerd > /dev/null ; then
    for i in $(docker ps -a -q); do
      timeout 10 docker inspect "$i" > "$info_system"/docker/container-"$i".txt 2>&1
      if [ $? -eq 124 ]; then
        touch "$info_system"/docker/container-inspect-timed-out.txt
        failed "'docker inspect' timed out, not gathering containers"
        return 1
      fi

      if grep --quiet "ECS_ENGINE_AUTH_DATA" "$info_system"/docker/container-"$i".txt; then
        sed -i 's/ECS_ENGINE_AUTH_DATA=.*/ECS_ENGINE_AUTH_DATA=/g' "$info_system"/docker/container-"$i".txt
      fi
    done
  else
    warning "the Docker daemon is not running." | tee "$info_system"/docker/docker-not-running.txt
    return 1
  fi
  ok
}

get_docker_sysconfig() {
  try "collect Docker sysconfig"

  if [ -e /etc/sysconfig/docker ]; then
    mkdir -p "${info_system}"/docker
    cp /etc/sysconfig/docker "${info_system}"/docker/sysconfig-docker
    ok
  else
    info "/etc/sysconfig/docker not found"
  fi

 try "collect Docker storage sysconfig"

  if [ -e /etc/sysconfig/docker-storage ]; then
    mkdir -p "${info_system}"/docker
    cp /etc/sysconfig/docker-storage "${info_system}"/docker/sysconfig-docker-storage
    ok
  else
    info "/etc/sysconfig/docker-storage not found"
  fi
}

get_docker_daemon_json(){
  try "collect Docker daemon.json"

  if [ -e /etc/docker/daemon.json ]; then
    mkdir -p "${info_system}"/docker
    cp /etc/docker/daemon.json "${info_system}"/docker/daemon.json
    ok
  else
    info "/etc/docker/daemon.json not found"
  fi
}

get_docker_systemd_config(){

  if [[ "$init_type" != "systemd" ]]; then
    return 0
  fi

  try "collect Docker systemd unit file"

  mkdir -p "${info_system}"/docker
  if systemctl cat docker.service > "${info_system}"/docker/docker.service 2>/dev/null; then
   ok
  else
    rm -f "$info_system/docker/docker.service"
    warning "docker.service not found"
  fi

  try "collect containerd systemd unit file"
  if systemctl cat containerd.service > "${info_system}"/docker/containerd.service 2>/dev/null; then
   ok
  else
    rm -f "$info_system/docker/containerd.service"
    warning "containerd.service not found"
  fi
}

get_os_release(){
  try "collect /etc/os-release"

  if [ -f /etc/os-release ]; then
    cat /etc/os-release > "${info_system}"/os-release
    ok
  else
    info "/etc/os-release not found"
  fi
}

get_cgroupv2_events(){
  # cgroup v2 is only supported on systemd systems
  if [[ "$init_type" != "systemd" ]]; then
    return 0
  fi
  # this file will only exist on systems with cgroup v2 enabled
  if [ ! -f /sys/fs/cgroup/cgroup.controllers ]; then
    return 0
  fi
  try "collect cgroupv2 events"

  local outfile="${info_system}"/cgroupv2.events
  touch $outfile
  # find cgroup memory event files for all ecs tasks with task resource limits and all
  # docker containers running on the system.
  for eventfile in $(find /sys/fs/cgroup/ -type f -name "memory*events" | grep -e "docker-" -e "ecstask"); do
    echo "$eventfile" >> $outfile
    cat $eventfile >> $outfile
    echo "" >> $outfile
  done
  ok
}

get_systemd_slice_info(){
  if [[ "$init_type" != "systemd" ]]; then
    return 0
  fi
  try "collect systemd slice info"

  # system.slice will exist on all systemd systems:
  local outfile="${info_system}"/system.slice
  touch $outfile
  systemctl status system.slice >$outfile
  # ecstasks.slice will only exist if we're using the systemd cgroup driver and cgroups v2:
  if systemctl status ecstasks.slice &>/dev/null; then
    local outfile="${info_system}"/ecstasks.slice
    touch $outfile
    systemctl status ecstasks.slice >$outfile
  fi
  ok
}

enable_docker_debug() {
  try "enable debug mode for the Docker daemon"

  if [ -e /etc/sysconfig/docker ] && grep -q "^\\s*OPTIONS=\"-D" /etc/sysconfig/docker; then
    info "Debug mode is already enabled."
  else

    if [ -e /etc/sysconfig/docker ]; then
      case "${init_type}" in
        systemd)
          sed -i 's/^OPTIONS="\(.*\)/OPTIONS="-D \1/g' /etc/sysconfig/docker
          ok

          try "restart Docker daemon to enable debug mode"
          systemctl restart docker.service
          ok
          ;;
        *)
          echo "OPTIONS=\"-D \$OPTIONS\"" >> /etc/sysconfig/docker

          try "restart Docker daemon to enable debug mode"
          service docker restart
          ok

        esac

    else
      warning "the current operating system is not supported."
    fi
  fi
}

enable_ecs_agent_debug() {
  try "enable debug mode for the Amazon ECS Container Agent"

  if [ -e /etc/ecs/ecs.config ] &&  grep -q "^\\s*ECS_LOGLEVEL=debug" /etc/ecs/ecs.config; then
    info "Debug mode is already enabled."
  else

    case "${init_type}" in
    systemd)
      if [ ! -d /etc/ecs ]; then
        mkdir /etc/ecs
      fi

      echo "ECS_LOGLEVEL=debug" >> /etc/ecs/ecs.config
      ok

      try "restart the Amazon ECS Container Agent to enable debug mode"
      systemctl restart ecs
      ok
      ;;
    *)
      if rpm -q --quiet ecs-init; then
        if [ ! -d /etc/ecs ]; then
          mkdir /etc/ecs
        fi

        echo "ECS_LOGLEVEL=debug" >> /etc/ecs/ecs.config
        ok

        try "restart the Amazon ECS Container Agent to enable debug mode"
        stop ecs; start ecs
        ok
      else
        warning "the current operating system is not supported."
      fi
      ;;
    esac
  fi
}

# nvidia-smi is a tool available on GPU based AMIs provides detailed
# information about the GPU present on the VM.
get_gpu_info() {
  try "get gpu info"

  if command -v nvidia-smi &>/dev/null; then
    mkdir -p "$info_system"/gpu
    nvidia-smi -L > "$info_system"/gpu/gpu-list.txt
    nvidia-smi -q > "$info_system"/gpu/gpu-info.txt
  fi

  ok
}
# --------------------------------------------------------------------------------------------

parse_options "$@"

case "${mode}" in
  brief)
    cleanup
    collect_brief
    pack
    ;;
  enable-debug)
    enable_debug
    ;;
  *)
    help && exit 1
    ;;
esac


#!/usr/bin/env bash

PROJECT_DIR=""
SDK_SOURCE_DIR=$(cd `dirname $0` && pwd)

usage() {
  echo "Usage: $0 [-s SDK_SOURCE_DIR] [-d PROJECT_DIR]" 1>&2
  exit 1
}

while getopts "hs:d:" options; do
  case "${options}" in
  s)
    SDK_SOURCE_DIR=${OPTARG}
    if [ "$SDK_SOURCE_DIR" == "" ]; then
      echo "path to SDK source directory is required" || exit
      usage
    fi
    ;;
  d)
    PROJECT_DIR=${OPTARG}
    ;;
  h)
    usage
    ;;
  *)
    usage
    ;;
  esac
done

if [ "$PROJECT_DIR" != "" ]; then
  cd "$PROJECT_DIR" || exit
fi

go mod graph | awk '{print $1}' | cut -d '@' -f 1 | sort | uniq | grep "github.com/aws/aws-sdk-go-v2" | while read x; do
  repPath=${x/github.com\/aws\/aws-sdk-go-v2/${SDK_SOURCE_DIR}}
  echo -replace $x=$repPath
done | xargs go mod edit


#1/usr/bin/env bash

PROJECT_DIR=""
SMITHY_SOURCE_DIR=$(cd `dirname $0` && pwd)

usage() {
  echo "Usage: $0 [-s SMITHY_SOURCE_DIR] [-d PROJECT_DIR]" 1>&2
  exit 1
}

while getopts "hs:d:" options; do
  case "${options}" in
  s)
    SMITHY_SOURCE_DIR=${OPTARG}
    if [ "$SMITHY_SOURCE_DIR" == "" ]; then
      echo "path to smithy-go source directory is required" || exit
      usage
    fi
    ;;
  d)
    PROJECT_DIR=${OPTARG}
    ;;
  h)
    usage
    ;;
  *)
    usage
    ;;
  esac
done

if [ "$PROJECT_DIR" != "" ]; then
  cd $PROJECT_DIR || exit
fi

go mod graph | awk '{print $1}' | cut -d '@' -f 1 | sort | uniq | grep "github.com/aws/smithy-go" | while read x; do
  repPath=${x/github.com\/aws\/smithy-go/${SMITHY_SOURCE_DIR}}
  echo -replace $x=$repPath
done | xargs go mod edit


#!/bin/bash
set -eu -o pipefail

# Small convenience script for running the tests with various combinations of
# arch/tags. This assumes we're running on amd64 and have qemu available.

go test ./...
go test -tags purego ./...
GOARCH=arm64 go test
GOARCH=arm64 go test -tags purego


#!/usr/bin/env bash
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

# This script runs or (given -n) prints suggested commands to generate files for
# the Architecture/OS specified by the GOARCH and GOOS environment variables.
# See README.md for more information about how the build system works.

GOOSARCH="${GOOS}_${GOARCH}"

# defaults
mksyscall="go run mksyscall.go"
mkerrors="./mkerrors.sh"
zerrors="zerrors_$GOOSARCH.go"
mksysctl=""
zsysctl="zsysctl_$GOOSARCH.go"
mksysnum=
mktypes=
mkasm=
run="sh"
cmd=""

case "$1" in
-syscalls)
	for i in zsyscall*go
	do
		# Run the command line that appears in the first line
		# of the generated file to regenerate it.
		sed 1q $i | sed 's;^// ;;' | sh > _$i && gofmt < _$i > $i
		rm _$i
	done
	exit 0
	;;
-n)
	run="cat"
	cmd="echo"
	shift
esac

case "$#" in
0)
	;;
*)
	echo 'usage: mkall.sh [-n]' 1>&2
	exit 2
esac

if [[ "$GOOS" = "linux" ]]; then
	# Use the Docker-based build system
	# Files generated through docker (use $cmd so you can Ctl-C the build or run)
	$cmd docker build --tag generate:$GOOS $GOOS
	$cmd docker run --interactive --tty --volume $(cd -- "$(dirname -- "$0")/.." && /bin/pwd):/build generate:$GOOS
	exit
fi

GOOSARCH_in=syscall_$GOOSARCH.go
case "$GOOSARCH" in
_* | *_ | _)
	echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
	exit 1
	;;
aix_ppc)
	mkerrors="$mkerrors -maix32"
	mksyscall="go run mksyscall_aix_ppc.go -aix"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
aix_ppc64)
	mkerrors="$mkerrors -maix64"
	mksyscall="go run mksyscall_aix_ppc64.go -aix"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
darwin_amd64)
	mkerrors="$mkerrors -m64"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	mkasm="go run mkasm.go"
	;;
darwin_arm64)
	mkerrors="$mkerrors -m64"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	mkasm="go run mkasm.go"
	;;
dragonfly_amd64)
	mkerrors="$mkerrors -m64"
	mksyscall="go run mksyscall.go -dragonfly"
	mksysnum="go run mksysnum.go 'https://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master'"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
freebsd_386)
	mkerrors="$mkerrors -m32"
	mksyscall="go run mksyscall.go -l32"
	mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
freebsd_amd64)
	mkerrors="$mkerrors -m64"
	mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
freebsd_arm)
	mkerrors="$mkerrors"
	mksyscall="go run mksyscall.go -l32 -arm"
	mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
	# Let the type of C char be signed for making the bare syscall
	# API consistent across platforms.
	mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
	;;
freebsd_arm64)
	mkerrors="$mkerrors -m64"
	mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
	;;
freebsd_riscv64)
	mkerrors="$mkerrors -m64"
	mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
	;;
netbsd_386)
	mkerrors="$mkerrors -m32"
	mksyscall="go run mksyscall.go -l32 -netbsd"
	mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
netbsd_amd64)
	mkerrors="$mkerrors -m64"
	mksyscall="go run mksyscall.go -netbsd"
	mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
netbsd_arm)
	mkerrors="$mkerrors"
	mksyscall="go run mksyscall.go -l32 -netbsd -arm"
	mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
	# Let the type of C char be signed for making the bare syscall
	# API consistent across platforms.
	mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
	;;
netbsd_arm64)
	mkerrors="$mkerrors -m64"
	mksyscall="go run mksyscall.go -netbsd"
	mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
openbsd_386)
	mkasm="go run mkasm.go"
	mkerrors="$mkerrors -m32"
	mksyscall="go run mksyscall.go -l32 -openbsd -libc"
	mksysctl="go run mksysctl_openbsd.go"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
openbsd_amd64)
	mkasm="go run mkasm.go"
	mkerrors="$mkerrors -m64"
	mksyscall="go run mksyscall.go -openbsd -libc"
	mksysctl="go run mksysctl_openbsd.go"
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
openbsd_arm)
	mkasm="go run mkasm.go"
	mkerrors="$mkerrors"
	mksyscall="go run mksyscall.go -l32 -openbsd -arm -libc"
	mksysctl="go run mksysctl_openbsd.go"
	# Let the type of C char be signed for making the bare syscall
	# API consistent across platforms.
	mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
	;;
openbsd_arm64)
	mkasm="go run mkasm.go"
	mkerrors="$mkerrors -m64"
	mksyscall="go run mksyscall.go -openbsd -libc"
	mksysctl="go run mksysctl_openbsd.go"
	# Let the type of C char be signed for making the bare syscall
	# API consistent across platforms.
	mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
	;;
openbsd_mips64)
	mkasm="go run mkasm.go"
	mkerrors="$mkerrors -m64"
	mksyscall="go run mksyscall.go -openbsd -libc"
	mksysctl="go run mksysctl_openbsd.go"
	# Let the type of C char be signed for making the bare syscall
	# API consistent across platforms.
	mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
	;;
openbsd_ppc64)
	mkasm="go run mkasm.go"
	mkerrors="$mkerrors -m64"
	mksyscall="go run mksyscall.go -openbsd -libc"
	mksysctl="go run mksysctl_openbsd.go"
	# Let the type of C char be signed for making the bare syscall
	# API consistent across platforms.
	mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
	;;
openbsd_riscv64)
	mkasm="go run mkasm.go"
	mkerrors="$mkerrors -m64"
	mksyscall="go run mksyscall.go -openbsd -libc"
	mksysctl="go run mksysctl_openbsd.go"
	# Let the type of C char be signed for making the bare syscall
	# API consistent across platforms.
	mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
	;;
solaris_amd64)
	mksyscall="go run mksyscall_solaris.go"
	mkerrors="$mkerrors -m64"
	mksysnum=
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
illumos_amd64)
        mksyscall="go run mksyscall_solaris.go"
	mkerrors=
	mksysnum=
	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
	;;
*)
	echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
	exit 1
	;;
esac

(
	if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi
	case "$GOOS" in
	*)
		syscall_goos="syscall_$GOOS.go"
		case "$GOOS" in
		darwin | dragonfly | freebsd | netbsd | openbsd)
			syscall_goos="syscall_bsd.go $syscall_goos"
			;;
		esac
		if [ -n "$mksyscall" ]; then
			if [ "$GOOSARCH" == "aix_ppc64" ]; then
				# aix/ppc64 script generates files instead of writing to stdin.
				echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in && gofmt -w zsyscall_$GOOSARCH.go && gofmt -w zsyscall_"$GOOSARCH"_gccgo.go && gofmt -w zsyscall_"$GOOSARCH"_gc.go " ;
			elif [ "$GOOS" == "illumos" ]; then
			        # illumos code generation requires a --illumos switch
			        echo "$mksyscall -illumos -tags illumos,$GOARCH syscall_illumos.go |gofmt > zsyscall_illumos_$GOARCH.go";
			        # illumos implies solaris, so solaris code generation is also required
				echo "$mksyscall -tags solaris,$GOARCH syscall_solaris.go syscall_solaris_$GOARCH.go |gofmt >zsyscall_solaris_$GOARCH.go";
			else
				echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go";
			fi
		fi
	esac
	if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
	if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
	if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go"; fi
	if [ -n "$mkasm" ]; then echo "$mkasm $GOOS $GOARCH"; fi
) | $run


#!/usr/bin/env bash
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

# Generate Go code listing errors and other #defined constant
# values (ENAMETOOLONG etc.), by asking the preprocessor
# about the definitions.

unset LANG
export LC_ALL=C
export LC_CTYPE=C

if test -z "$GOARCH" -o -z "$GOOS"; then
	echo 1>&2 "GOARCH or GOOS not defined in environment"
	exit 1
fi

# Check that we are using the new build system if we should
if [[ "$GOOS" = "linux" ]] && [[ "$GOLANG_SYS_BUILD" != "docker" ]]; then
	echo 1>&2 "In the Docker based build system, mkerrors should not be called directly."
	echo 1>&2 "See README.md"
	exit 1
fi

if [[ "$GOOS" = "aix" ]]; then
	CC=${CC:-gcc}
else
	CC=${CC:-cc}
fi

if [[ "$GOOS" = "solaris" ]]; then
	# Assumes GNU versions of utilities in PATH.
	export PATH=/usr/gnu/bin:$PATH
fi

uname=$(uname)

includes_AIX='
#include <net/if.h>
#include <net/netopt.h>
#include <netinet/ip_mroute.h>
#include <sys/protosw.h>
#include <sys/stropts.h>
#include <sys/mman.h>
#include <sys/poll.h>
#include <sys/select.h>
#include <sys/termio.h>
#include <termios.h>
#include <fcntl.h>

#define AF_LOCAL AF_UNIX
'

includes_Darwin='
#define _DARWIN_C_SOURCE
#define KERNEL 1
#define _DARWIN_USE_64_BIT_INODE
#define __APPLE_USE_RFC_3542
#include <stdint.h>
#include <sys/attr.h>
#include <sys/clonefile.h>
#include <sys/kern_control.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/ptrace.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/sockio.h>
#include <sys/sys_domain.h>
#include <sys/sysctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <sys/xattr.h>
#include <sys/vsock.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <termios.h>

// for backwards compatibility because moved TIOCREMOTE to Kernel.framework after MacOSX12.0.sdk.
#define TIOCREMOTE 0x80047469
'

includes_DragonFly='
#include <sys/types.h>
#include <sys/event.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_clone.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
#include <termios.h>
#include <netinet/ip.h>
#include <net/ip_mroute/ip_mroute.h>
'

includes_FreeBSD='
#include <sys/capsicum.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/disk.h>
#include <sys/event.h>
#include <sys/sched.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/sockio.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/ptrace.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
#include <termios.h>
#include <netinet/ip.h>
#include <netinet/ip_mroute.h>
#include <sys/extattr.h>

#if __FreeBSD__ >= 10
#define IFT_CARP	0xf8	// IFT_CARP is deprecated in FreeBSD 10
#undef SIOCAIFADDR
#define SIOCAIFADDR	_IOW(105, 26, struct oifaliasreq)	// ifaliasreq contains if_data
#undef SIOCSIFPHYADDR
#define SIOCSIFPHYADDR	_IOW(105, 70, struct oifaliasreq)	// ifaliasreq contains if_data
#endif
'

includes_Linux='
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#ifndef __LP64__
#define _FILE_OFFSET_BITS 64
#endif
#define _GNU_SOURCE

// <sys/ioctl.h> is broken on powerpc64, as it fails to include definitions of
// these structures. We just include them copied from <bits/termios.h>.
#if defined(__powerpc__)
struct sgttyb {
        char    sg_ispeed;
        char    sg_ospeed;
        char    sg_erase;
        char    sg_kill;
        short   sg_flags;
};

struct tchars {
        char    t_intrc;
        char    t_quitc;
        char    t_startc;
        char    t_stopc;
        char    t_eofc;
        char    t_brkc;
};

struct ltchars {
        char    t_suspc;
        char    t_dsuspc;
        char    t_rprntc;
        char    t_flushc;
        char    t_werasc;
        char    t_lnextc;
};
#endif

#include <bits/sockaddr.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <sys/inotify.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/signalfd.h>
#include <sys/socket.h>
#include <sys/timerfd.h>
#include <sys/uio.h>
#include <sys/xattr.h>
#include <netinet/udp.h>
#include <linux/audit.h>
#include <linux/bpf.h>
#include <linux/can.h>
#include <linux/can/error.h>
#include <linux/can/netlink.h>
#include <linux/can/raw.h>
#include <linux/capability.h>
#include <linux/cryptouser.h>
#include <linux/devlink.h>
#include <linux/dm-ioctl.h>
#include <linux/errqueue.h>
#include <linux/ethtool_netlink.h>
#include <linux/falloc.h>
#include <linux/fanotify.h>
#include <linux/fib_rules.h>
#include <linux/filter.h>
#include <linux/fs.h>
#include <linux/fscrypt.h>
#include <linux/fsverity.h>
#include <linux/genetlink.h>
#include <linux/hdreg.h>
#include <linux/hidraw.h>
#include <linux/if.h>
#include <linux/if_addr.h>
#include <linux/if_alg.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/if_ppp.h>
#include <linux/if_tun.h>
#include <linux/if_packet.h>
#include <linux/if_xdp.h>
#include <linux/input.h>
#include <linux/kcm.h>
#include <linux/kexec.h>
#include <linux/keyctl.h>
#include <linux/landlock.h>
#include <linux/loop.h>
#include <linux/lwtunnel.h>
#include <linux/magic.h>
#include <linux/memfd.h>
#include <linux/module.h>
#include <linux/mount.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netlink.h>
#include <linux/net_namespace.h>
#include <linux/nfc.h>
#include <linux/nsfs.h>
#include <linux/perf_event.h>
#include <linux/pps.h>
#include <linux/ptrace.h>
#include <linux/random.h>
#include <linux/reboot.h>
#include <linux/rtc.h>
#include <linux/rtnetlink.h>
#include <linux/sched.h>
#include <linux/seccomp.h>
#include <linux/serial.h>
#include <linux/sockios.h>
#include <linux/taskstats.h>
#include <linux/tipc.h>
#include <linux/vm_sockets.h>
#include <linux/wait.h>
#include <linux/watchdog.h>
#include <linux/wireguard.h>

#include <mtd/ubi-user.h>
#include <mtd/mtd-user.h>
#include <net/route.h>

#if defined(__sparc__)
// On sparc{,64}, the kernel defines struct termios2 itself which clashes with the
// definition in glibc. As only the error constants are needed here, include the
// generic termibits.h (which is included by termbits.h on sparc).
#include <asm-generic/termbits.h>
#else
#include <asm/termbits.h>
#endif

#ifndef MSG_FASTOPEN
#define MSG_FASTOPEN    0x20000000
#endif

#ifndef PTRACE_GETREGS
#define PTRACE_GETREGS	0xc
#endif

#ifndef PTRACE_SETREGS
#define PTRACE_SETREGS	0xd
#endif

#ifndef SOL_NETLINK
#define SOL_NETLINK	270
#endif

#ifndef SOL_SMC
#define SOL_SMC 286
#endif

#ifdef SOL_BLUETOOTH
// SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h
// but it is already in bluetooth_linux.go
#undef SOL_BLUETOOTH
#endif

// Certain constants are missing from the fs/crypto UAPI
#define FS_KEY_DESC_PREFIX              "fscrypt:"
#define FS_KEY_DESC_PREFIX_SIZE         8
#define FS_MAX_KEY_SIZE                 64

// The code generator produces -0x1 for (~0), but an unsigned value is necessary
// for the tipc_subscr timeout __u32 field.
#undef TIPC_WAIT_FOREVER
#define TIPC_WAIT_FOREVER 0xffffffff

// Copied from linux/l2tp.h
// Including linux/l2tp.h here causes conflicts between linux/in.h
// and netinet/in.h included via net/route.h above.
#define IPPROTO_L2TP		115

// Copied from linux/hid.h.
// Keep in sync with the size of the referenced fields.
#define _HIDIOCGRAWNAME_LEN	128 // sizeof_field(struct hid_device, name)
#define _HIDIOCGRAWPHYS_LEN	64  // sizeof_field(struct hid_device, phys)
#define _HIDIOCGRAWUNIQ_LEN	64  // sizeof_field(struct hid_device, uniq)

#define _HIDIOCGRAWNAME		HIDIOCGRAWNAME(_HIDIOCGRAWNAME_LEN)
#define _HIDIOCGRAWPHYS		HIDIOCGRAWPHYS(_HIDIOCGRAWPHYS_LEN)
#define _HIDIOCGRAWUNIQ		HIDIOCGRAWUNIQ(_HIDIOCGRAWUNIQ_LEN)

'

includes_NetBSD='
#include <sys/types.h>
#include <sys/param.h>
#include <sys/event.h>
#include <sys/extattr.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/sched.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/termios.h>
#include <sys/ttycom.h>
#include <sys/wait.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_mroute.h>
#include <netinet/if_ether.h>

// Needed since <sys/param.h> refers to it...
#define schedppq 1
'

includes_OpenBSD='
#include <sys/types.h>
#include <sys/param.h>
#include <sys/event.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/select.h>
#include <sys/sched.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/termios.h>
#include <sys/ttycom.h>
#include <sys/unistd.h>
#include <sys/wait.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/if_var.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_mroute.h>
#include <netinet/if_ether.h>
#include <net/if_bridge.h>

// We keep some constants not supported in OpenBSD 5.5 and beyond for
// the promise of compatibility.
#define EMUL_ENABLED		0x1
#define EMUL_NATIVE		0x2
#define IPV6_FAITH		0x1d
#define IPV6_OPTIONS		0x1
#define IPV6_RTHDR_STRICT	0x1
#define IPV6_SOCKOPT_RESERVED1	0x3
#define SIOCGIFGENERIC		0xc020693a
#define SIOCSIFGENERIC		0x80206939
#define WALTSIG			0x4
'

includes_SunOS='
#include <limits.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/stat.h>
#include <sys/stream.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/mkdev.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/icmp6.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_mroute.h>
#include <termios.h>
'

includes='
#include <sys/types.h>
#include <sys/file.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <sys/signal.h>
#include <signal.h>
#include <sys/resource.h>
#include <time.h>
'
ccflags="$@"

# Write go tool cgo -godefs input.
(
	echo package unix
	echo
	echo '/*'
	indirect="includes_$(uname)"
	echo "${!indirect} $includes"
	echo '*/'
	echo 'import "C"'
	echo 'import "syscall"'
	echo
	echo 'const ('

	# The gcc command line prints all the #defines
	# it encounters while processing the input
	echo "${!indirect} $includes" | $CC -x c - -E -dM $ccflags |
	awk '
		$1 != "#define" || $2 ~ /\(/ || $3 == "" {next}

		$2 ~ /^E([ABCD]X|[BIS]P|[SD]I|S|FL)$/ {next}  # 386 registers
		$2 ~ /^(SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))/ {next}
		$2 ~ /^(SCM_SRCRT)$/ {next}
		$2 ~ /^(MAP_FAILED)$/ {next}
		$2 ~ /^ELF_.*$/ {next}# <asm/elf.h> contains ELF_ARCH, etc.

		$2 ~ /^EXTATTR_NAMESPACE_NAMES/ ||
		$2 ~ /^EXTATTR_NAMESPACE_[A-Z]+_STRING/ {next}

		$2 !~ /^ECCAPBITS/ &&
		$2 !~ /^ETH_/ &&
		$2 !~ /^EPROC_/ &&
		$2 !~ /^EQUIV_/ &&
		$2 !~ /^EXPR_/ &&
		$2 !~ /^EVIOC/ &&
		$2 ~ /^E[A-Z0-9_]+$/ ||
		$2 ~ /^B[0-9_]+$/ ||
		$2 ~ /^(OLD|NEW)DEV$/ ||
		$2 == "BOTHER" ||
		$2 ~ /^CI?BAUD(EX)?$/ ||
		$2 == "IBSHIFT" ||
		$2 ~ /^V[A-Z0-9]+$/ ||
		$2 ~ /^CS[A-Z0-9]/ ||
		$2 ~ /^I(SIG|CANON|CRNL|UCLC|EXTEN|MAXBEL|STRIP|UTF8)$/ ||
		$2 ~ /^IGN/ ||
		$2 ~ /^IX(ON|ANY|OFF)$/ ||
		$2 ~ /^IN(LCR|PCK)$/ ||
		$2 !~ "X86_CR3_PCID_NOFLUSH" &&
		$2 ~ /(^FLU?SH)|(FLU?SH$)/ ||
		$2 ~ /^C(LOCAL|READ|MSPAR|RTSCTS)$/ ||
		$2 == "BRKINT" ||
		$2 == "HUPCL" ||
		$2 == "PENDIN" ||
		$2 == "TOSTOP" ||
		$2 == "XCASE" ||
		$2 == "ALTWERASE" ||
		$2 == "NOKERNINFO" ||
		$2 == "NFDBITS" ||
		$2 ~ /^PAR/ ||
		$2 ~ /^SIG[^_]/ ||
		$2 ~ /^O[CNPFPL][A-Z]+[^_][A-Z]+$/ ||
		$2 ~ /^(NL|CR|TAB|BS|VT|FF)DLY$/ ||
		$2 ~ /^(NL|CR|TAB|BS|VT|FF)[0-9]$/ ||
		$2 ~ /^O?XTABS$/ ||
		$2 ~ /^TC[IO](ON|OFF)$/ ||
		$2 ~ /^IN_/ ||
		$2 ~ /^KCM/ ||
		$2 ~ /^LANDLOCK_/ ||
		$2 ~ /^LOCK_(SH|EX|NB|UN)$/ ||
		$2 ~ /^LO_(KEY|NAME)_SIZE$/ ||
		$2 ~ /^LOOP_(CLR|CTL|GET|SET)_/ ||
		$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|MCAST|EVFILT|NOTE|SHUT|PROT|MAP|MFD|T?PACKET|MSG|SCM|MCL|DT|MADV|PR|LOCAL|TCPOPT|UDP)_/ ||
		$2 ~ /^NFC_(GENL|PROTO|COMM|RF|SE|DIRECTION|LLCP|SOCKPROTO)_/ ||
		$2 ~ /^NFC_.*_(MAX)?SIZE$/ ||
		$2 ~ /^RAW_PAYLOAD_/ ||
		$2 ~ /^[US]F_/ ||
		$2 ~ /^TP_STATUS_/ ||
		$2 ~ /^FALLOC_/ ||
		$2 ~ /^ICMPV?6?_(FILTER|SEC)/ ||
		$2 == "SOMAXCONN" ||
		$2 == "NAME_MAX" ||
		$2 == "IFNAMSIZ" ||
		$2 ~ /^CTL_(HW|KERN|MAXNAME|NET|QUERY)$/ ||
		$2 ~ /^KERN_(HOSTNAME|OS(RELEASE|TYPE)|VERSION)$/ ||
		$2 ~ /^HW_MACHINE$/ ||
		$2 ~ /^SYSCTL_VERS/ ||
		$2 !~ "MNT_BITS" &&
		$2 ~ /^(MS|MNT|MOUNT|UMOUNT)_/ ||
		$2 ~ /^NS_GET_/ ||
		$2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ ||
		$2 ~ /^(O|F|[ES]?FD|NAME|S|PTRACE|PT|PIOD|TFD)_/ ||
		$2 ~ /^KEXEC_/ ||
		$2 ~ /^LINUX_REBOOT_CMD_/ ||
		$2 ~ /^LINUX_REBOOT_MAGIC[12]$/ ||
		$2 ~ /^MODULE_INIT_/ ||
		$2 !~ "NLA_TYPE_MASK" &&
		$2 !~ /^RTC_VL_(ACCURACY|BACKUP|DATA)/ &&
		$2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTC|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P|NETNSA)_/ ||
		$2 ~ /^FIORDCHK$/ ||
		$2 ~ /^SIOC/ ||
		$2 ~ /^TIOC/ ||
		$2 ~ /^TCGET/ ||
		$2 ~ /^TCSET/ ||
		$2 ~ /^TC(FLSH|SBRKP?|XONC)$/ ||
		$2 !~ "RTF_BITS" &&
		$2 ~ /^(IFF|IFT|NET_RT|RTM(GRP)?|RTF|RTV|RTA|RTAX)_/ ||
		$2 ~ /^BIOC/ ||
		$2 ~ /^DIOC/ ||
		$2 ~ /^RUSAGE_(SELF|CHILDREN|THREAD)/ ||
		$2 ~ /^RLIMIT_(AS|CORE|CPU|DATA|FSIZE|LOCKS|MEMLOCK|MSGQUEUE|NICE|NOFILE|NPROC|RSS|RTPRIO|RTTIME|SIGPENDING|STACK)|RLIM_INFINITY/ ||
		$2 ~ /^PRIO_(PROCESS|PGRP|USER)/ ||
		$2 ~ /^CLONE_[A-Z_]+/ ||
		$2 !~ /^(BPF_TIMEVAL|BPF_FIB_LOOKUP_[A-Z]+)$/ &&
		$2 ~ /^(BPF|DLT)_/ ||
		$2 ~ /^AUDIT_/ ||
		$2 ~ /^(CLOCK|TIMER)_/ ||
		$2 ~ /^CAN_/ ||
		$2 ~ /^CAP_/ ||
		$2 ~ /^CP_/ ||
		$2 ~ /^CPUSTATES$/ ||
		$2 ~ /^CTLIOCGINFO$/ ||
		$2 ~ /^ALG_/ ||
		$2 ~ /^FI(CLONE|DEDUPERANGE)/ ||
		$2 ~ /^FS_(POLICY_FLAGS|KEY_DESC|ENCRYPTION_MODE|[A-Z0-9_]+_KEY_SIZE)/ ||
		$2 ~ /^FS_IOC_.*(ENCRYPTION|VERITY|[GS]ETFLAGS)/ ||
		$2 ~ /^FS_VERITY_/ ||
		$2 ~ /^FSCRYPT_/ ||
		$2 ~ /^DM_/ ||
		$2 ~ /^GRND_/ ||
		$2 ~ /^RND/ ||
		$2 ~ /^KEY_(SPEC|REQKEY_DEFL)_/ ||
		$2 ~ /^KEYCTL_/ ||
		$2 ~ /^PERF_/ ||
		$2 ~ /^SECCOMP_MODE_/ ||
		$2 ~ /^SEEK_/ ||
		$2 ~ /^SPLICE_/ ||
		$2 ~ /^SYNC_FILE_RANGE_/ ||
		$2 !~ /IOC_MAGIC/ &&
		$2 ~ /^[A-Z][A-Z0-9_]+_MAGIC2?$/ ||
		$2 ~ /^(VM|VMADDR)_/ ||
		$2 ~ /^IOCTL_VM_SOCKETS_/ ||
		$2 ~ /^(TASKSTATS|TS)_/ ||
		$2 ~ /^CGROUPSTATS_/ ||
		$2 ~ /^GENL_/ ||
		$2 ~ /^STATX_/ ||
		$2 ~ /^RENAME/ ||
		$2 ~ /^UBI_IOC[A-Z]/ ||
		$2 ~ /^UTIME_/ ||
		$2 ~ /^XATTR_(CREATE|REPLACE|NO(DEFAULT|FOLLOW|SECURITY)|SHOWCOMPRESSION)/ ||
		$2 ~ /^ATTR_(BIT_MAP_COUNT|(CMN|VOL|FILE)_)/ ||
		$2 ~ /^FSOPT_/ ||
		$2 ~ /^WDIO[CFS]_/ ||
		$2 ~ /^NFN/ ||
		$2 ~ /^XDP_/ ||
		$2 ~ /^RWF_/ ||
		$2 ~ /^(HDIO|WIN|SMART)_/ ||
		$2 ~ /^CRYPTO_/ ||
		$2 ~ /^TIPC_/ ||
		$2 !~  "DEVLINK_RELOAD_LIMITS_VALID_MASK" &&
		$2 ~ /^DEVLINK_/ ||
		$2 ~ /^ETHTOOL_/ ||
		$2 ~ /^LWTUNNEL_IP/ ||
		$2 ~ /^ITIMER_/ ||
		$2 !~ "WMESGLEN" &&
		$2 ~ /^W[A-Z0-9]+$/ ||
		$2 ~ /^P_/ ||
		$2 ~/^PPPIOC/ ||
		$2 ~ /^FAN_|FANOTIFY_/ ||
		$2 == "HID_MAX_DESCRIPTOR_SIZE" ||
		$2 ~ /^_?HIDIOC/ ||
		$2 ~ /^BUS_(USB|HIL|BLUETOOTH|VIRTUAL)$/ ||
		$2 ~ /^MTD/ ||
		$2 ~ /^OTP/ ||
		$2 ~ /^MEM/ ||
		$2 ~ /^WG/ ||
		$2 ~ /^FIB_RULE_/ ||
		$2 ~ /^BLK[A-Z]*(GET$|SET$|BUF$|PART$|SIZE)/ {printf("\t%s = C.%s\n", $2, $2)}
		$2 ~ /^__WCOREFLAG$/ {next}
		$2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)}

		{next}
	' | sort

	echo ')'
) >_const.go

# Pull out the error names for later.
errors=$(
	echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
	awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print $2 }' |
	sort
)

# Pull out the signal names for later.
signals=$(
	echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
	awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' |
	grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT\|SIGMAX64' |
	sort
)

# Again, writing regexps to a file.
echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
	awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print "^\t" $2 "[ \t]*=" }' |
	sort >_error.grep
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
	awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' |
	grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT\|SIGMAX64' |
	sort >_signal.grep

echo '// mkerrors.sh' "$@"
echo '// Code generated by the command above; see README.md. DO NOT EDIT.'
echo
echo "//go:build ${GOARCH} && ${GOOS}"
echo "// +build ${GOARCH},${GOOS}"
echo
go tool cgo -godefs -- "$@" _const.go >_error.out
cat _error.out | grep -vf _error.grep | grep -vf _signal.grep
echo
echo '// Errors'
echo 'const ('
cat _error.out | grep -f _error.grep | sed 's/=\(.*\)/= syscall.Errno(\1)/'
echo ')'

echo
echo '// Signals'
echo 'const ('
cat _error.out | grep -f _signal.grep | sed 's/=\(.*\)/= syscall.Signal(\1)/'
echo ')'

# Run C program to print error and syscall strings.
(
	echo -E "
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <signal.h>

#define nelem(x) (sizeof(x)/sizeof((x)[0]))

enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below

struct tuple {
	int num;
	const char *name;
};

struct tuple errors[] = {
"
	for i in $errors
	do
		echo -E '	{'$i', "'$i'" },'
	done

	echo -E "
};

struct tuple signals[] = {
"
	for i in $signals
	do
		echo -E '	{'$i', "'$i'" },'
	done

	# Use -E because on some systems bash builtin interprets \n itself.
	echo -E '
};

static int
tuplecmp(const void *a, const void *b)
{
	return ((struct tuple *)a)->num - ((struct tuple *)b)->num;
}

int
main(void)
{
	int i, e;
	char buf[1024], *p;

	printf("\n\n// Error table\n");
	printf("var errorList = [...]struct {\n");
	printf("\tnum  syscall.Errno\n");
	printf("\tname string\n");
	printf("\tdesc string\n");
	printf("} {\n");
	qsort(errors, nelem(errors), sizeof errors[0], tuplecmp);
	for(i=0; i<nelem(errors); i++) {
		e = errors[i].num;
		if(i > 0 && errors[i-1].num == e)
			continue;
		strcpy(buf, strerror(e));
		// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
		if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
			buf[0] += a - A;
		printf("\t{ %d, \"%s\", \"%s\" },\n", e, errors[i].name, buf);
	}
	printf("}\n\n");

	printf("\n\n// Signal table\n");
	printf("var signalList = [...]struct {\n");
	printf("\tnum  syscall.Signal\n");
	printf("\tname string\n");
	printf("\tdesc string\n");
	printf("} {\n");
	qsort(signals, nelem(signals), sizeof signals[0], tuplecmp);
	for(i=0; i<nelem(signals); i++) {
		e = signals[i].num;
		if(i > 0 && signals[i-1].num == e)
			continue;
		strcpy(buf, strsignal(e));
		// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
		if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
			buf[0] += a - A;
		// cut trailing : number.
		p = strrchr(buf, ":"[0]);
		if(p)
			*p = '\0';
		printf("\t{ %d, \"%s\", \"%s\" },\n", e, signals[i].name, buf);
	}
	printf("}\n\n");

	return 0;
}

'
) >_errors.c

$CC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.go _error.grep _signal.grep _error.out