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 me="${0##*/}"
     40 msg()
     41 {
     42 	printf >&2 '%s\n' "$me: $*"
     43 }
     44 
     45 prefix=
     46 case $# in
     47 	1)	inc_dir="$1"; shift
     48 		;;
     49 	2)	inc_dir="$1"; shift
     50 		prefix="$1"; shift
     51 		;;
     52 	*)	echo >&2 "usage: $me include-directory [prefix]"
     53 		exit 1
     54 		;;
     55 esac
     56 
     57 [ -z "$prefix" ] ||
     58 	prefix="${prefix%%/}/"
     59 
     60 tmpdir=
     61 cleanup()
     62 {
     63 	trap - EXIT
     64 	[ -z "$tmpdir" ] ||
     65 		rm -rf -- "$tmpdir"
     66 	exit "$@"
     67 }
     68 
     69 trap 'cleanup $?' EXIT
     70 trap 'cleanup 1' HUP PIPE INT QUIT TERM
     71 tmpdir="$(mktemp -dt "$me.XXXXXX")"
     72 
     73 # list interesting files in $inc_dir.
     74 cd "$inc_dir"
     75 inc_dir="$(pwd -P)"
     76 find . -type f -name '*.h' -print0 |
     77 	xargs -r0 grep -l "$r_value" -- > "$tmpdir"/headers1.list ||
     78 		exit 0
     79 cd - > /dev/null
     80 sed 's|^\./\(uapi/\)\?||' < "$tmpdir"/headers1.list > "$tmpdir"/headers.list
     81 LC_COLLATE=C sort -u -o "$tmpdir"/headers.list "$tmpdir"/headers.list
     82 
     83 msg "processing $(wc -l < "$tmpdir"/headers.list) header files from $inc_dir"
     84 failed=0
     85 
     86 CC="${CC:-gcc}"
     87 CPP="${CPP:-cpp}"
     88 CPPFLAGS="${CPPFLAGS-} -D__EXPORTED_HEADERS__"
     89 CFLAGS="${CFLAGS:--Wall -O2} -D__EXPORTED_HEADERS__"
     90 LDFLAGS="${LDFLAGS-}"
     91 INCLUDES="-I$inc_dir/uapi -I$inc_dir ${INCLUDES-}"
     92 
     93 $CC $INCLUDES $CFLAGS -c -o "$tmpdir"/print_ioctlent.o "${0%/*}"/print_ioctlent.c
     94 
     95 # Hook onto <asm-generic/ioctl.h> and <asm/ioctl.h>
     96 for d in asm-generic asm; do
     97 	mkdir "$tmpdir/$d"
     98 	cat > "$tmpdir/$d"/ioctl.h <<__EOF__
     99 #include_next <$d/ioctl.h>
    100 #undef _IOC
    101 #define _IOC(dir,type,nr,size) dir, type, nr, size
    102 __EOF__
    103 done
    104 
    105 INCLUDES="-I$tmpdir $INCLUDES"
    106 
    107 process_file()
    108 {
    109 	local f="$1"; shift
    110 
    111 	# Common code for every processed file.
    112 	cat > "$tmpdir"/printents.c <<__EOF__
    113 #include <asm/termbits.h>
    114 #include <asm/ioctl.h>
    115 #include <linux/types.h>
    116 #include <linux/limits.h>
    117 #include <linux/major.h>
    118 
    119 #include <sys/types.h>
    120 #include <sys/socket.h>
    121 #include <stdint.h>
    122 #include <stdbool.h>
    123 
    124 #ifndef NULL
    125 # define NULL ((void*)0)
    126 #endif
    127 #ifndef __user
    128 # define __user
    129 #endif
    130 #ifndef __iomem
    131 # define __iomem
    132 #endif
    133 #ifndef __noreturn
    134 # define __noreturn __attribute__((noreturn))
    135 #endif
    136 #ifndef __packed
    137 # define __packed __attribute__((packed))
    138 #endif
    139 
    140 typedef signed char s8;
    141 typedef unsigned char u8;
    142 typedef signed short s16;
    143 typedef unsigned short u16;
    144 typedef signed int s32;
    145 typedef unsigned int u32;
    146 typedef signed long long s64;
    147 typedef unsigned long long u64;
    148 
    149 #include "fixes.h"
    150 
    151 #include <asm/bitsperlong.h>
    152 #ifndef BITS_PER_LONG
    153 # define BITS_PER_LONG __BITS_PER_LONG
    154 #endif
    155 
    156 #include "$f"
    157 
    158 void print_ioctlent(const char *, const char *, unsigned short, unsigned short, unsigned short, unsigned short);
    159 
    160 int main(void)
    161 {
    162 
    163 #include "defs.h"
    164 
    165 return 0;
    166 }
    167 __EOF__
    168 
    169 	# Soft workarounds for some processed files.  Fragile.
    170 	case "$f" in
    171 		*asm/cmb.h)
    172 			echo '#include <asm/dasd.h>'
    173 			;;
    174 		*asm/ioctls.h)
    175 			cat <<'__EOF__'
    176 #include <asm/termios.h>
    177 #include <linux/serial.h>
    178 __EOF__
    179 			;;
    180 		*drm/*_drm.h)
    181 			echo '#include <drm/drm.h>'
    182 			;;
    183 		fbio.h|*/fbio.h)
    184 			cat <<'__EOF__'
    185 #include <linux/fb.h>
    186 #undef FBIOGETCMAP
    187 #undef FBIOPUTCMAP
    188 __EOF__
    189 			;;
    190 		*linux/atm?*.h)
    191 			echo '#include <linux/atm.h>'
    192 			;;
    193 		*linux/auto_fs*.h)
    194 			echo 'typedef u32 compat_ulong_t;'
    195 			;;
    196 		*linux/btrfs.h)
    197 			cat <<'__EOF__'
    198 struct btrfs_ioctl_defrag_range_args { __u32 unused[12]; };
    199 #define BTRFS_LABEL_SIZE 256
    200 __EOF__
    201 			;;
    202 		*linux/coda.h|*android_alarm.h)
    203 			cat <<'__EOF__'
    204 #ifndef _LINUX_TIME_H
    205 # define _LINUX_TIME_H
    206 #endif
    207 #ifndef _UAPI_LINUX_TIME_H
    208 # define _UAPI_LINUX_TIME_H
    209 #endif
    210 __EOF__
    211 			;;
    212 		*linux/fs.h|*linux/ncp_fs.h)
    213 			cat <<'__EOF__'
    214 #include <linux/blktrace_api.h>
    215 #include <linux/fiemap.h>
    216 __EOF__
    217 			;;
    218 		*linux/if_pppox.h)
    219 			cat <<'__EOF__'
    220 #include <linux/if.h>
    221 #include <linux/in.h>
    222 #include <linux/in6.h>
    223 __EOF__
    224 			;;
    225 		*linux/if_tun.h|*linux/ppp-ioctl.h)
    226 			echo '#include <linux/filter.h>'
    227 			;;
    228 		*linux/isdn_ppp.h|*linux/gsmmux.h)
    229 			echo '#include <linux/if.h>'
    230 			;;
    231 		*media/saa6588.h)
    232 			echo 'typedef struct poll_table_struct poll_table;'
    233 			;;
    234 		*linux/ivtvfb.h|*linux/meye.h|*media/*.h)
    235 			echo '#include <linux/videodev2.h>'
    236 			;;
    237 		*linux/kvm.h)
    238 			cat <<'__EOF__'
    239 #if defined __x86_64__ || defined __i386__
    240 struct kvm_allocate_rma { __u32 unused[2]; };
    241 struct kvm_create_spapr_tce { __u32 unused[3]; };
    242 struct kvm_get_htab_fd { __u32 unused[8]; };
    243 struct kvm_rtas_token_args { __u8 unused[128]; };
    244 struct kvm_vcpu_init { __u32 unused[8]; };
    245 #elif defined __arm64__ || defined __arm__
    246 struct kvm_allocate_rma { __u32 unused[2]; };
    247 struct kvm_cpuid { __u32 unused[2]; };
    248 struct kvm_cpuid2 { __u32 unused[2]; };
    249 struct kvm_create_spapr_tce { __u32 unused[3]; };
    250 struct kvm_debugregs { __u32 unused[32]; };
    251 struct kvm_get_htab_fd { __u32 unused[8]; };
    252 struct kvm_lapic_state { __u32 unused[256]; };
    253 struct kvm_memory_alias { __u32 unused[8]; };
    254 struct kvm_msr_list { __u32 unused[1]; };
    255 struct kvm_msrs { __u32 unused[2]; };
    256 struct kvm_pit_state { __u32 unused[18]; };
    257 struct kvm_pit_state2 { __u32 unused[28]; };
    258 struct kvm_rtas_token_args { __u32 unused[128]; };
    259 struct kvm_vcpu_events { __u32 unused[16]; };
    260 struct kvm_x86_mce { __u32 unused[16]; };
    261 struct kvm_xcrs { __u32 unused[98]; };
    262 struct kvm_xen_hvm_config { __u32 unused[14]; };
    263 struct kvm_xsave { __u32 unused[1024]; };
    264 #endif
    265 __EOF__
    266 			;;
    267 		*linux/sonet.h)
    268 			echo '#include <linux/atmioc.h>'
    269 			;;
    270 		*linux/usbdevice_fs.h)
    271 			cat <<'__EOF__'
    272 struct usbdevfs_ctrltransfer32 { __u32 unused[4]; };
    273 struct usbdevfs_bulktransfer32 { __u32 unused[4]; };
    274 struct usbdevfs_disconnectsignal32 { __u32 unused[2]; };
    275 struct usbdevfs_urb32 { __u8 unused[42]; };
    276 struct usbdevfs_ioctl32 { __u32 unused[3]; };
    277 __EOF__
    278 			;;
    279 		logger.h|*/logger.h)
    280 			echo 'typedef __u32 kuid_t;'
    281 			;;
    282 		*sound/asequencer.h)
    283 			cat <<'__EOF__'
    284 #include <sound/asound.h>
    285 struct snd_seq_queue_owner { __u32 unused[0]; };
    286 __EOF__
    287 			;;
    288 		*sound/emu10k1.h)
    289 			cat <<'__EOF__'
    290 #include <sound/asound.h>
    291 #ifndef DECLARE_BITMAP
    292 # define DIV_ROUND_UP(x,y) (((x) + ((y) - 1)) / (y))
    293 # define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, 8 * sizeof(long))
    294 # define DECLARE_BITMAP(name,bits) unsigned long name[BITS_TO_LONGS(bits)]
    295 #endif
    296 __EOF__
    297 			;;
    298 		*video/sstfb.h)
    299 			echo 'struct fb_info;'
    300 			;;
    301 		*xen/interface/*.h)
    302 			return 0 # false positives
    303 			;;
    304 		*xen/privcmd.h)
    305 			return 0 # too much work to make it compileable
    306 			;;
    307 	esac > "$tmpdir"/fixes.h
    308 
    309 	cat > "$tmpdir"/header.in <<__EOF__
    310 #include <asm/bitsperlong.h>
    311 #ifndef BITS_PER_LONG
    312 # define BITS_PER_LONG __BITS_PER_LONG
    313 #endif
    314 #include "$f"
    315 __EOF__
    316 
    317 	if [ -f "$inc_dir/uapi/$f" ]; then
    318 		s="$inc_dir/uapi/$f"
    319 	elif [ -f "$inc_dir/$f" ]; then
    320 		s="$inc_dir/$f"
    321 	else
    322 		msg "$f: file not found"
    323 		return 1
    324 	fi
    325 
    326 	[ -n "${f##*/*}" ] ||
    327 		mkdir -p "$tmpdir/${f%/*}"
    328 	# Hard workarounds for some processed files.  Very fragile.
    329 	case "$f" in
    330 		*acpi/*|*linux/i2o.h|*media/exynos-fimc.h|*media/v4l2-subdev.h|*net/bluetooth/*)
    331 			# Fetch macros only.
    332 			grep "${r_define}${r_cmd_name}" < "$s" > "$tmpdir/$f"
    333 			;;
    334 		binder.h|*/binder.h)
    335 			# Convert enums to macros.
    336 			sed '/^enum binder/,/^};/d' < "$s" > "$tmpdir/$f"
    337 			sed -n '/^enum binder/,/^};/ s/^[[:space:]].*/&/p' < "$s" |
    338 			sed -e '
    339 s/^[[:space:]]*\([A-Z][A-Z_0-9]*\)[[:space:]]*=[[:space:]]*_\(IO\|IOW\|IOR\|IOWR\|IOC\)[[:space:]]*(/#define \1 _\2(/
    340 s/^\(#define .*)\),$/\1/
    341 s/^\(#define .*,\)$/\1 \\/
    342 s/^\([[:space:]]\+[^),]\+)\),$/\1/' >> "$tmpdir/$f"
    343 			;;
    344 		*drm/r128_drm.h)
    345 			# Filter out the code that references unknown types.
    346 			sed '/drm_r128_clear2_t/d' < "$s" > "$tmpdir/$f"
    347 			;;
    348 		*drm/sis_drm.h)
    349 			# Filter out the code that references unknown types.
    350 			sed '/^struct sis_file_private/,/^}/d' < "$s" > "$tmpdir/$f"
    351 			;;
    352 		*drm/via_drm.h)
    353 			# Create the file it attempts to include.
    354 			touch "$tmpdir/via_drmclient.h"
    355 			# Filter out the code that references unknown types.
    356 			sed '/^struct via_file_private/,/^}/d' < "$s" > "$tmpdir/$f"
    357 			;;
    358 		*linux/vmw_vmci_defs.h)
    359 			# Fetch ioctl macros only.
    360 			grep "${r_define}I" < "$s" > "$tmpdir/$f"
    361 			;;
    362 		*media/v4l2-common.h)
    363 			# Fetch one piece of code containing ioctls definitions.
    364 			sed -n '/ remaining ioctls/,/ ---/p' < "$s" > "$tmpdir/$f"
    365 			;;
    366 		*linux/nilfs2_fs.h)
    367 			# Create the file it attempts to include.
    368 			touch "$tmpdir/asm/bug.h"
    369 			;;
    370 		openpromio.h|*/openpromio.h|fbio.h|*/fbio.h)
    371 			# Create the file it attempts to include.
    372 			mkdir -p "$tmpdir/linux"
    373 			touch "$tmpdir/linux/compiler.h"
    374 	esac
    375 	if [ -f "$tmpdir/$f" ]; then
    376 		s="$tmpdir/$f"
    377 	fi
    378 
    379 	# This may fail if the file includes unavailable headers.
    380 	# In case of success it outputs both the #define directives
    381 	# and the result of preprocessing.
    382 	$CPP $CPPFLAGS -dD $INCLUDES < "$tmpdir"/header.in > "$tmpdir"/header.out
    383 
    384 	# Need to exclude ioctl commands defined elsewhere.
    385 	local_defines='^[[:space:]]*#[[:space:]]*define[[:space:]]\+\('"$r_cmd_name"'\)[[:space:]]'
    386 	sed -n 's/'"$local_defines"'.*/\1\\/p' "$s" > "$tmpdir"/local_names
    387 	r_local_names="$(tr '\n' '|' < "$tmpdir"/local_names)"
    388 	r_local_names="${r_local_names%%|}"
    389 	r_local_names="${r_local_names%%\\}"
    390 
    391 	# Keep this in sync with $regexp by replacing $r_cmd_name with $r_local_names.
    392 	defs_regexp="${r_define}\($r_local_names\)${r_value}"
    393 
    394 	qf="$(echo "$prefix$f" | sed 's/[&\/]/\\&/g')"
    395 	# This outputs lines in the following format:
    396 	# print_ioctlent("filename.h", "IOCTL_CMD_NAME", IOCTL_CMD_NAME);
    397 	sed -n 's/'"$defs_regexp"'.*/print_ioctlent("'"$qf"'", "\1", \1);/p' \
    398 		< "$tmpdir"/header.out > "$tmpdir"/defs.h
    399 
    400 	# If something is wrong with the file, this will fail.
    401 	$CC $INCLUDES $CFLAGS -c -o "$tmpdir"/printents.o "$tmpdir"/printents.c
    402 	$CC $LDFLAGS -o "$tmpdir"/print_ioctlents \
    403 		"$tmpdir"/printents.o "$tmpdir"/print_ioctlent.o
    404 	"$tmpdir"/print_ioctlents > "$tmpdir"/ioctlents
    405 	cat "$tmpdir"/ioctlents
    406 	msg "$f: fetched $(grep -c '^{' "$tmpdir"/ioctlents) ioctl entries"
    407 }
    408 
    409 while read f; do
    410 	(process_file "$f" < /dev/null)
    411 	[ $? -eq 0 ] || {
    412 		msg "$f: failed to process"
    413 		failed=$((1 + $failed))
    414 	}
    415 done < "$tmpdir"/headers.list
    416 
    417 [ $failed -eq 0 ] ||
    418 	msg "failed to process $failed file(s)"
    419