mkerrors.sh raw

   1  #!/usr/bin/env bash
   2  # Copyright 2009 The Go Authors. All rights reserved.
   3  # Use of this source code is governed by a BSD-style
   4  # license that can be found in the LICENSE file.
   5  
   6  # Generate Go code listing errors and other #defined constant
   7  # values (ENAMETOOLONG etc.), by asking the preprocessor
   8  # about the definitions.
   9  
  10  unset LANG
  11  export LC_ALL=C
  12  export LC_CTYPE=C
  13  
  14  CC=${CC:-gcc}
  15  
  16  uname=$(uname)
  17  
  18  includes='
  19  #include <sys/types.h>
  20  #include <sys/file.h>
  21  #include <fcntl.h>
  22  #include <dirent.h>
  23  #include <sys/socket.h>
  24  #include <netinet/in.h>
  25  #include <netinet/ip.h>
  26  #include <netinet/ip6.h>
  27  #include <netinet/tcp.h>
  28  #include <errno.h>
  29  #include <sys/signal.h>
  30  #include <signal.h>
  31  #include <sys/resource.h>
  32  '
  33  
  34  ccflags="$@"
  35  
  36  # Write go tool cgo -godefs input.
  37  (
  38  	echo package plan9
  39  	echo
  40  	echo '/*'
  41  	indirect="includes_$(uname)"
  42  	echo "${!indirect} $includes"
  43  	echo '*/'
  44  	echo 'import "C"'
  45  	echo
  46  	echo 'const ('
  47  
  48  	# The gcc command line prints all the #defines
  49  	# it encounters while processing the input
  50  	echo "${!indirect} $includes" | $CC -x c - -E -dM $ccflags |
  51  	awk '
  52  		$1 != "#define" || $2 ~ /\(/ || $3 == "" {next}
  53  
  54  		$2 ~ /^E([ABCD]X|[BIS]P|[SD]I|S|FL)$/ {next}  # 386 registers
  55  		$2 ~ /^(SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))/ {next}
  56  		$2 ~ /^(SCM_SRCRT)$/ {next}
  57  		$2 ~ /^(MAP_FAILED)$/ {next}
  58  
  59  		$2 !~ /^ETH_/ &&
  60  		$2 !~ /^EPROC_/ &&
  61  		$2 !~ /^EQUIV_/ &&
  62  		$2 !~ /^EXPR_/ &&
  63  		$2 ~ /^E[A-Z0-9_]+$/ ||
  64  		$2 ~ /^B[0-9_]+$/ ||
  65  		$2 ~ /^V[A-Z0-9]+$/ ||
  66  		$2 ~ /^CS[A-Z0-9]/ ||
  67  		$2 ~ /^I(SIG|CANON|CRNL|EXTEN|MAXBEL|STRIP|UTF8)$/ ||
  68  		$2 ~ /^IGN/ ||
  69  		$2 ~ /^IX(ON|ANY|OFF)$/ ||
  70  		$2 ~ /^IN(LCR|PCK)$/ ||
  71  		$2 ~ /(^FLU?SH)|(FLU?SH$)/ ||
  72  		$2 ~ /^C(LOCAL|READ)$/ ||
  73  		$2 == "BRKINT" ||
  74  		$2 == "HUPCL" ||
  75  		$2 == "PENDIN" ||
  76  		$2 == "TOSTOP" ||
  77  		$2 ~ /^PAR/ ||
  78  		$2 ~ /^SIG[^_]/ ||
  79  		$2 ~ /^O[CNPFP][A-Z]+[^_][A-Z]+$/ ||
  80  		$2 ~ /^IN_/ ||
  81  		$2 ~ /^LOCK_(SH|EX|NB|UN)$/ ||
  82  		$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|ICMP6|TCP|EVFILT|NOTE|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|MCL|DT|MADV|PR)_/ ||
  83  		$2 == "ICMPV6_FILTER" ||
  84  		$2 == "SOMAXCONN" ||
  85  		$2 == "NAME_MAX" ||
  86  		$2 == "IFNAMSIZ" ||
  87  		$2 ~ /^CTL_(MAXNAME|NET|QUERY)$/ ||
  88  		$2 ~ /^SYSCTL_VERS/ ||
  89  		$2 ~ /^(MS|MNT)_/ ||
  90  		$2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ ||
  91  		$2 ~ /^(O|F|FD|NAME|S|PTRACE|PT)_/ ||
  92  		$2 ~ /^LINUX_REBOOT_CMD_/ ||
  93  		$2 ~ /^LINUX_REBOOT_MAGIC[12]$/ ||
  94  		$2 !~ "NLA_TYPE_MASK" &&
  95  		$2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P)_/ ||
  96  		$2 ~ /^SIOC/ ||
  97  		$2 ~ /^TIOC/ ||
  98  		$2 !~ "RTF_BITS" &&
  99  		$2 ~ /^(IFF|IFT|NET_RT|RTM|RTF|RTV|RTA|RTAX)_/ ||
 100  		$2 ~ /^BIOC/ ||
 101  		$2 ~ /^RUSAGE_(SELF|CHILDREN|THREAD)/ ||
 102  		$2 ~ /^RLIMIT_(AS|CORE|CPU|DATA|FSIZE|NOFILE|STACK)|RLIM_INFINITY/ ||
 103  		$2 ~ /^PRIO_(PROCESS|PGRP|USER)/ ||
 104  		$2 ~ /^CLONE_[A-Z_]+/ ||
 105  		$2 !~ /^(BPF_TIMEVAL)$/ &&
 106  		$2 ~ /^(BPF|DLT)_/ ||
 107  		$2 !~ "WMESGLEN" &&
 108  		$2 ~ /^W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", $2, $2)}
 109  		$2 ~ /^__WCOREFLAG$/ {next}
 110  		$2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)}
 111  
 112  		{next}
 113  	' | sort
 114  
 115  	echo ')'
 116  ) >_const.go
 117  
 118  # Pull out the error names for later.
 119  errors=$(
 120  	echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
 121  	awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print $2 }' |
 122  	sort
 123  )
 124  
 125  # Pull out the signal names for later.
 126  signals=$(
 127  	echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
 128  	awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' |
 129  	grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT' |
 130  	sort
 131  )
 132  
 133  # Again, writing regexps to a file.
 134  echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
 135  	awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print "^\t" $2 "[ \t]*=" }' |
 136  	sort >_error.grep
 137  echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
 138  	awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' |
 139  	grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT' |
 140  	sort >_signal.grep
 141  
 142  echo '// mkerrors.sh' "$@"
 143  echo '// Code generated by the command above; DO NOT EDIT.'
 144  echo
 145  go tool cgo -godefs -- "$@" _const.go >_error.out
 146  cat _error.out | grep -vf _error.grep | grep -vf _signal.grep
 147  echo
 148  echo '// Errors'
 149  echo 'const ('
 150  cat _error.out | grep -f _error.grep | sed 's/=\(.*\)/= Errno(\1)/'
 151  echo ')'
 152  
 153  echo
 154  echo '// Signals'
 155  echo 'const ('
 156  cat _error.out | grep -f _signal.grep | sed 's/=\(.*\)/= Signal(\1)/'
 157  echo ')'
 158  
 159  # Run C program to print error and syscall strings.
 160  (
 161  	echo -E "
 162  #include <stdio.h>
 163  #include <stdlib.h>
 164  #include <errno.h>
 165  #include <ctype.h>
 166  #include <string.h>
 167  #include <signal.h>
 168  
 169  #define nelem(x) (sizeof(x)/sizeof((x)[0]))
 170  
 171  enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below
 172  
 173  int errors[] = {
 174  "
 175  	for i in $errors
 176  	do
 177  		echo -E '	'$i,
 178  	done
 179  
 180  	echo -E "
 181  };
 182  
 183  int signals[] = {
 184  "
 185  	for i in $signals
 186  	do
 187  		echo -E '	'$i,
 188  	done
 189  
 190  	# Use -E because on some systems bash builtin interprets \n itself.
 191  	echo -E '
 192  };
 193  
 194  static int
 195  intcmp(const void *a, const void *b)
 196  {
 197  	return *(int*)a - *(int*)b;
 198  }
 199  
 200  int
 201  main(void)
 202  {
 203  	int i, j, e;
 204  	char buf[1024], *p;
 205  
 206  	printf("\n\n// Error table\n");
 207  	printf("var errors = [...]string {\n");
 208  	qsort(errors, nelem(errors), sizeof errors[0], intcmp);
 209  	for(i=0; i<nelem(errors); i++) {
 210  		e = errors[i];
 211  		if(i > 0 && errors[i-1] == e)
 212  			continue;
 213  		strcpy(buf, strerror(e));
 214  		// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
 215  		if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
 216  			buf[0] += a - A;
 217  		printf("\t%d: \"%s\",\n", e, buf);
 218  	}
 219  	printf("}\n\n");
 220  	
 221  	printf("\n\n// Signal table\n");
 222  	printf("var signals = [...]string {\n");
 223  	qsort(signals, nelem(signals), sizeof signals[0], intcmp);
 224  	for(i=0; i<nelem(signals); i++) {
 225  		e = signals[i];
 226  		if(i > 0 && signals[i-1] == e)
 227  			continue;
 228  		strcpy(buf, strsignal(e));
 229  		// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
 230  		if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
 231  			buf[0] += a - A;
 232  		// cut trailing : number.
 233  		p = strrchr(buf, ":"[0]);
 234  		if(p)
 235  			*p = '\0';
 236  		printf("\t%d: \"%s\",\n", e, buf);
 237  	}
 238  	printf("}\n\n");
 239  
 240  	return 0;
 241  }
 242  
 243  '
 244  ) >_errors.c
 245  
 246  $CC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.go _error.grep _signal.grep _error.out
 247