Home | History | Annotate | Download | only in maint
      1 #!/bin/sh
      2 # Copyright (c) 2015 Dmitry V. Levin <ldv (at] altlinux.org>
      3 # All rights reserved.
      4 #
      5 # Redistribution and use in source and binary forms, with or without
      6 # modification, are permitted provided that the following conditions
      7 # are met:
      8 # 1. Redistributions of source code must retain the above copyright
      9 #    notice, this list of conditions and the following disclaimer.
     10 # 2. Redistributions in binary form must reproduce the above copyright
     11 #    notice, this list of conditions and the following disclaimer in the
     12 #    documentation and/or other materials provided with the distribution.
     13 # 3. The name of the author may not be used to endorse or promote products
     14 #    derived from this software without specific prior written permission.
     15 #
     16 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17 # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18 # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26 
     27 set -efu
     28 
     29 # This script processes header files containing ioctl command definitions in
     30 # symbolic form, assuming that these definitions match the following regular
     31 # expressions:
     32 
     33 r_define='^[[:space:]]*#[[:space:]]*define[[:space:]]\+'
     34 r_cmd_name='[A-Z][A-Z0-9_]*'
     35 r_io='\([A-Z]\+\)\?_S\?\(IO\|IOW\|IOR\|IOWR\|IOC\)'
     36 r_value='[[:space:]]\+'"$r_io"'[[:space:]]*([^)]'
     37 regexp="${r_define}${r_cmd_name}${r_value}"
     38 
     39 uname_m="$(uname -m)"
     40 me="${0##*/}"
     41 msg()
     42 {
     43 	printf >&2 '%s\n' "$me: $*"
     44 }
     45 
     46 prefix=
     47 case $# in
     48 	1)	inc_dir="$1"; shift
     49 		;;
     50 	2)	inc_dir="$1"; shift
     51 		prefix="$1"; shift
     52 		;;
     53 	*)	echo >&2 "usage: $me include-directory [prefix]"
     54 		exit 1
     55 		;;
     56 esac
     57 
     58 [ -z "$prefix" ] ||
     59 	prefix="${prefix%%/}/"
     60 
     61 tmpdir=
     62 cleanup()
     63 {
     64 	trap - EXIT
     65 	[ -z "$tmpdir" ] ||
     66 		rm -rf -- "$tmpdir"
     67 	exit "$@"
     68 }
     69 
     70 trap 'cleanup $?' EXIT
     71 trap 'cleanup 1' HUP PIPE INT QUIT TERM
     72 tmpdir="$(mktemp -dt "$me.XXXXXX")"
     73 
     74 # list interesting files in $inc_dir.
     75 cd "$inc_dir"
     76 inc_dir="$(pwd -P)"
     77 find . -type f -name '*.h' -print0 |
     78 	xargs -r0 grep -l "$r_value" -- > "$tmpdir"/headers1.list ||
     79 		exit 0
     80 cd - > /dev/null
     81 sed 's|^\./\(uapi/\)\?||' < "$tmpdir"/headers1.list > "$tmpdir"/headers.list
     82 LC_COLLATE=C sort -u -o "$tmpdir"/headers.list "$tmpdir"/headers.list
     83 
     84 msg "processing $(wc -l < "$tmpdir"/headers.list) header files from $inc_dir"
     85 failed=0
     86 
     87 CC="${CC:-gcc}"
     88 CPP="${CPP:-cpp}"
     89 CPPFLAGS="${CPPFLAGS-} -D__EXPORTED_HEADERS__"
     90 CFLAGS="${CFLAGS:--Wall -O2} -D__EXPORTED_HEADERS__"
     91 LDFLAGS="${LDFLAGS-}"
     92 INCLUDES="-I$inc_dir/uapi -I$inc_dir ${INCLUDES-}"
     93 
     94 $CC $INCLUDES $CFLAGS -c -o "$tmpdir"/print_ioctlent.o "${0%/*}"/print_ioctlent.c
     95 
     96 # Hook onto <asm-generic/ioctl.h> and <asm/ioctl.h>
     97 for d in asm-generic asm; do
     98 	mkdir "$tmpdir/$d"
     99 	cat > "$tmpdir/$d"/ioctl.h <<__EOF__
    100 #include_next <$d/ioctl.h>
    101 #undef _IOC
    102 #define _IOC(dir,type,nr,size) dir, type, nr, size
    103 __EOF__
    104 done
    105 
    106 INCLUDES="-I$tmpdir $INCLUDES"
    107 
    108 process_file()
    109 {
    110 	local f="$1"; shift
    111 
    112 	# Common code for every processed file.
    113 	cat > "$tmpdir"/printents.c <<__EOF__
    114 #include <asm/termbits.h>
    115 #include <asm/ioctl.h>
    116 #include <linux/types.h>
    117 #include <linux/limits.h>
    118 #include <linux/major.h>
    119 
    120 #include <sys/types.h>
    121 #include <sys/socket.h>
    122 #include <stdint.h>
    123 #include <stdbool.h>
    124 
    125 #ifndef NULL
    126 # define NULL ((void*)0)
    127 #endif
    128 #ifndef __user
    129 # define __user
    130 #endif
    131 #ifndef __iomem
    132 # define __iomem
    133 #endif
    134 #ifndef __noreturn
    135 # define __noreturn __attribute__((noreturn))
    136 #endif
    137 #ifndef __packed
    138 # define __packed __attribute__((packed))
    139 #endif
    140 
    141 typedef signed char s8;
    142 typedef unsigned char u8;
    143 typedef signed short s16;
    144 typedef unsigned short u16;
    145 typedef signed int s32;
    146 typedef unsigned int u32;
    147 typedef signed long long s64;
    148 typedef unsigned long long u64;
    149 
    150 #include "fixes.h"
    151 
    152 #include <asm/bitsperlong.h>
    153 #ifndef BITS_PER_LONG
    154 # define BITS_PER_LONG __BITS_PER_LONG
    155 #endif
    156 
    157 #include "$f"
    158 
    159 void print_ioctlent(const char *, const char *, unsigned short, unsigned short, unsigned short, unsigned short);
    160 
    161 int main(void)
    162 {
    163 
    164 #include "defs.h"
    165 
    166 return 0;
    167 }
    168 __EOF__
    169 
    170 	# Soft pre-include workarounds for some processed files.  Fragile.
    171 	case "$f" in
    172 		*asm/amigayle.h)
    173 			return 0 # false positive
    174 			;;
    175 		*asm/cmb.h)
    176 			echo '#include <asm/dasd.h>'
    177 			;;
    178 		*asm/core_*.h)
    179 			return 0 # false positives
    180 			;;
    181 		*asm/ioctls.h)
    182 			cat <<'__EOF__'
    183 #include <asm/termios.h>
    184 #include <linux/serial.h>
    185 __EOF__
    186 			;;
    187 		drm/sis_drm.h)
    188 			echo '#include <drm/drm.h>'
    189 			;;
    190 		*drm/*_drm.h)
    191 			echo '#include <drm/drm.h>' > "$tmpdir/drm.h"
    192 			;;
    193 		fbio.h|*/fbio.h)
    194 			cat <<'__EOF__'
    195 #include <linux/fb.h>
    196 #undef FBIOGETCMAP
    197 #undef FBIOPUTCMAP
    198 __EOF__
    199 			;;
    200 		*linux/atm_zatm.h)
    201 			cat <<'__EOF__'
    202 #include <linux/atm.h>
    203 #ifndef _LINUX_TIME_H
    204 # define _LINUX_TIME_H
    205 #endif
    206 #ifndef _UAPI_LINUX_TIME_H
    207 # define _UAPI_LINUX_TIME_H
    208 #endif
    209 __EOF__
    210 			;;
    211 		*linux/atm?*.h)
    212 			echo '#include <linux/atm.h>'
    213 			;;
    214 		*linux/auto_fs*.h)
    215 			echo 'typedef u32 compat_ulong_t;'
    216 			;;
    217 		*linux/coda.h|*android_alarm.h)
    218 			cat <<'__EOF__'
    219 #ifndef _LINUX_TIME_H
    220 # define _LINUX_TIME_H
    221 #endif
    222 #ifndef _UAPI_LINUX_TIME_H
    223 # define _UAPI_LINUX_TIME_H
    224 #endif
    225 __EOF__
    226 			;;
    227 		*linux/fs.h|*linux/ncp_fs.h)
    228 			cat <<'__EOF__'
    229 #include <linux/blktrace_api.h>
    230 #include <linux/fiemap.h>
    231 __EOF__
    232 			;;
    233 		*linux/if_pppox.h)
    234 			echo '#include <netinet/in.h>'
    235 			;;
    236 		*linux/if_tun.h|*linux/ppp-ioctl.h)
    237 			echo '#include <linux/filter.h>'
    238 			;;
    239 		*linux/isdn_ppp.h|*linux/gsmmux.h)
    240 			echo '#include <linux/if.h>'
    241 			;;
    242 		*media*/saa6588.h)
    243 			echo 'typedef struct poll_table_struct poll_table;'
    244 			;;
    245 		*linux/ivtvfb.h|*linux/meye.h|*media/*.h)
    246 			echo '#include <linux/videodev2.h>'
    247 			;;
    248 		*linux/kvm.h)
    249 			case "$uname_m" in
    250 				i?86|x86_64|arm*|ppc*|s390*) ;;
    251 				*) return 0 ;; # not applicable
    252 			esac
    253 			;;
    254 		*linux/sonet.h)
    255 			echo '#include <linux/atmioc.h>'
    256 			;;
    257 		*linux/usbdevice_fs.h)
    258 			cat <<'__EOF__'
    259 struct usbdevfs_ctrltransfer32 { __u32 unused[4]; };
    260 struct usbdevfs_bulktransfer32 { __u32 unused[4]; };
    261 struct usbdevfs_disconnectsignal32 { __u32 unused[2]; };
    262 struct usbdevfs_urb32 { __u8 unused[42]; };
    263 struct usbdevfs_ioctl32 { __u32 unused[3]; };
    264 __EOF__
    265 			;;
    266 		logger.h|*/logger.h)
    267 			echo 'typedef __u32 kuid_t;'
    268 			;;
    269 		*sound/asequencer.h)
    270 			cat <<'__EOF__'
    271 #include <sound/asound.h>
    272 struct snd_seq_queue_owner { __u32 unused[0]; };
    273 __EOF__
    274 			;;
    275 		*sound/emu10k1.h)
    276 			cat <<'__EOF__'
    277 #include <sound/asound.h>
    278 #ifndef DECLARE_BITMAP
    279 # define DIV_ROUND_UP(x,y) (((x) + ((y) - 1)) / (y))
    280 # define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, 8 * sizeof(long))
    281 # define DECLARE_BITMAP(name,bits) unsigned long name[BITS_TO_LONGS(bits)]
    282 #endif
    283 __EOF__
    284 			;;
    285 		*video/sstfb.h)
    286 			echo 'struct fb_info;'
    287 			;;
    288 		*xen/evtchn.h|*xen/gntdev.h)
    289 			cat <<'__EOF__'
    290 typedef uint32_t grant_ref_t;
    291 typedef uint16_t domid_t;
    292 __EOF__
    293 			;;
    294 		*xen/interface/*.h)
    295 			return 0 # false positives
    296 			;;
    297 		*xen/privcmd.h)
    298 			return 0 # too much work to make it compileable
    299 			;;
    300 	esac > "$tmpdir"/fixes.h
    301 
    302 	cat > "$tmpdir"/header.in <<__EOF__
    303 #include <asm/bitsperlong.h>
    304 #ifndef BITS_PER_LONG
    305 # define BITS_PER_LONG __BITS_PER_LONG
    306 #endif
    307 #include "$f"
    308 __EOF__
    309 
    310 	if [ -f "$inc_dir/uapi/$f" ]; then
    311 		s="$inc_dir/uapi/$f"
    312 	elif [ -f "$inc_dir/$f" ]; then
    313 		s="$inc_dir/$f"
    314 	else
    315 		msg "$f: file not found"
    316 		return 1
    317 	fi
    318 
    319 	[ -n "${f##*/*}" ] ||
    320 		mkdir -p "$tmpdir/${f%/*}"
    321 	# Hard workarounds for some processed files.  Very fragile.
    322 	case "$f" in
    323 		*asm-generic/ioctls.h)
    324 			# Filter out macros defined using unavailable types.
    325 			case "$uname_m" in
    326 				alpha*|ppc*)
    327 					grep -Fv 'struct termios2' < "$s" > "$tmpdir/$f"
    328 					;;
    329 			esac
    330 			;;
    331 		*acpi/*|*linux/i2o.h|*media*/exynos-fimc.h|*media/v4l2-subdev.h|*net/bluetooth/*|net/nfc/nci_core.h)
    332 			# Fetch macros only.
    333 			grep "${r_define}${r_cmd_name}" < "$s" > "$tmpdir/$f"
    334 			;;
    335 		binder.h|*/binder.h)
    336 			# Convert enums to macros.
    337 			sed '/^enum binder/,/^};/d' < "$s" > "$tmpdir/$f"
    338 			sed -n '/^enum binder/,/^};/ s/^[[:space:]].*/&/p' < "$s" |
    339 			sed -e '
    340 s/^[[:space:]]*\([A-Z][A-Z_0-9]*\)[[:space:]]*=[[:space:]]*_\(IO\|IOW\|IOR\|IOWR\|IOC\)[[:space:]]*(/#define \1 _\2(/
    341 s/^\(#define .*)\),$/\1/
    342 s/^\(#define .*,\)$/\1 \\/
    343 s/^\([[:space:]]\+[^),]\+)\),$/\1/' >> "$tmpdir/$f"
    344 			;;
    345 		*drm/r128_drm.h)
    346 			# Filter out the code that references unknown types.
    347 			sed '/drm_r128_clear2_t/d' < "$s" > "$tmpdir/$f"
    348 			;;
    349 		*drm/sis_drm.h)
    350 			# Filter out the code that references unknown types.
    351 			sed '/^struct sis_file_private/,/^}/d' < "$s" > "$tmpdir/$f"
    352 			;;
    353 		*drm/via_drm.h)
    354 			# Create the file it attempts to include.
    355 			touch "$tmpdir/via_drmclient.h"
    356 			# Filter out the code that references unknown types.
    357 			sed '/^struct via_file_private/,/^}/d' < "$s" > "$tmpdir/$f"
    358 			;;
    359 		*linux/nilfs2_fs.h)
    360 			# Create the file it attempts to include.
    361 			touch "$tmpdir/asm/bug.h"
    362 			;;
    363 		*linux/vmw_vmci_defs.h)
    364 			# Fetch ioctl macros only.
    365 			grep "${r_define}I" < "$s" > "$tmpdir/$f"
    366 			;;
    367 		*media/v4l2-common.h)
    368 			# Fetch one piece of code containing ioctls definitions.
    369 			sed -n '/ remaining ioctls/,/ ---/p' < "$s" > "$tmpdir/$f"
    370 			;;
    371 		openpromio.h|*/openpromio.h|fbio.h|*/fbio.h)
    372 			# Create the file it attempts to include.
    373 			mkdir -p "$tmpdir/linux"
    374 			touch "$tmpdir/linux/compiler.h"
    375 	esac
    376 	if [ -f "$tmpdir/$f" ]; then
    377 		s="$tmpdir/$f"
    378 	fi
    379 
    380 	# This may fail if the file includes unavailable headers.
    381 	# In case of success it outputs both the #define directives
    382 	# and the result of preprocessing.
    383 	$CPP $CPPFLAGS -dD $INCLUDES < "$tmpdir"/header.in > "$tmpdir"/header.out
    384 
    385 	# Soft post-preprocess workarounds.  Fragile.
    386 	case "$f" in
    387 		*linux/kvm.h)
    388 			arm_list='KVM_ARM_PREFERRED_TARGET|KVM_ARM_VCPU_INIT'
    389 			ppc_list='KVM_ALLOCATE_RMA|KVM_CREATE_SPAPR_TCE|KVM_CREATE_SPAPR_TCE_64|KVM_PPC_GET_HTAB_FD|KVM_PPC_RTAS_DEFINE_TOKEN'
    390 			x86_list='KVM_GET_CPUID2|KVM_GET_DEBUGREGS|KVM_GET_EMULATED_CPUID|KVM_GET_LAPIC|KVM_GET_MSRS|KVM_GET_MSR_INDEX_LIST|KVM_GET_PIT|KVM_GET_PIT2|KVM_GET_SUPPORTED_CPUID|KVM_GET_VCPU_EVENTS|KVM_GET_XCRS|KVM_GET_XSAVE|KVM_SET_CPUID|KVM_SET_CPUID2|KVM_SET_DEBUGREGS|KVM_SET_LAPIC|KVM_SET_MEMORY_ALIAS|KVM_SET_MSRS|KVM_SET_PIT|KVM_SET_PIT2|KVM_SET_VCPU_EVENTS|KVM_SET_XCRS|KVM_SET_XSAVE|KVM_X86_SET_MCE|KVM_XEN_HVM_CONFIG'
    391 			case "$uname_m" in
    392 				arm*) list="$ppc_list|$x86_list" ;;
    393 				ppc*) list="$arm_list|$x86_list" ;;
    394 				i?86|x86_64*) list="$arm_list|$ppc_list" ;;
    395 				*) list="$arm_list|$ppc_list|$x86_list" ;;
    396 			esac
    397 			sed -r -i "/[[:space:]]($list)[[:space:]]/d" "$tmpdir"/header.out
    398 			;;
    399 	esac
    400 
    401 	# Need to exclude ioctl commands defined elsewhere.
    402 	local_defines='^[[:space:]]*#[[:space:]]*define[[:space:]]\+\('"$r_cmd_name"'\)[[:space:]]'
    403 	sed -n 's/'"$local_defines"'.*/\1\\/p' "$s" > "$tmpdir"/local_names
    404 	r_local_names="$(tr '\n' '|' < "$tmpdir"/local_names)"
    405 	r_local_names="${r_local_names%%|}"
    406 	r_local_names="${r_local_names%%\\}"
    407 
    408 	# Keep this in sync with $regexp by replacing $r_cmd_name with $r_local_names.
    409 	defs_regexp="${r_define}\($r_local_names\)${r_value}"
    410 
    411 	qf="$(echo "$prefix$f" | sed 's/[&\/]/\\&/g')"
    412 	# This outputs lines in the following format:
    413 	# print_ioctlent("filename.h", "IOCTL_CMD_NAME", IOCTL_CMD_NAME);
    414 	sed -n 's/'"$defs_regexp"'.*/print_ioctlent("'"$qf"'", "\1", \1);/p' \
    415 		< "$tmpdir"/header.out > "$tmpdir"/defs.h
    416 
    417 	# If something is wrong with the file, this will fail.
    418 	$CC $INCLUDES $CFLAGS -c -o "$tmpdir"/printents.o "$tmpdir"/printents.c
    419 	$CC $LDFLAGS -o "$tmpdir"/print_ioctlents \
    420 		"$tmpdir"/printents.o "$tmpdir"/print_ioctlent.o
    421 	"$tmpdir"/print_ioctlents > "$tmpdir"/ioctlents
    422 	cat "$tmpdir"/ioctlents
    423 	msg "$f: fetched $(grep -c '^{' "$tmpdir"/ioctlents) ioctl entries"
    424 }
    425 
    426 while read f; do
    427 	(process_file "$f" < /dev/null)
    428 	[ $? -eq 0 ] || {
    429 		msg "$f: failed to process"
    430 		failed=$((1 + $failed))
    431 	}
    432 done < "$tmpdir"/headers.list
    433 
    434 [ $failed -eq 0 ] ||
    435 	msg "failed to process $failed file(s)"
    436