1#!/bin/sh 2# Copyright (c) 2015 Dmitry V. Levin <ldv@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 27set -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 33r_define='^[[:space:]]*#[[:space:]]*define[[:space:]]\+' 34r_cmd_name='[A-Z][A-Z0-9_]*' 35r_io='\([A-Z]\+\)\?_S\?\(IO\|IOW\|IOR\|IOWR\|IOC\)' 36r_value='[[:space:]]\+'"$r_io"'[[:space:]]*([^)]' 37regexp="${r_define}${r_cmd_name}${r_value}" 38 39uname_m="$(uname -m)" 40me="${0##*/}" 41msg() 42{ 43 printf >&2 '%s\n' "$me: $*" 44} 45 46prefix= 47case $# 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 ;; 56esac 57 58[ -z "$prefix" ] || 59 prefix="${prefix%%/}/" 60 61tmpdir= 62cleanup() 63{ 64 trap - EXIT 65 [ -z "$tmpdir" ] || 66 rm -rf -- "$tmpdir" 67 exit "$@" 68} 69 70trap 'cleanup $?' EXIT 71trap 'cleanup 1' HUP PIPE INT QUIT TERM 72tmpdir="$(mktemp -dt "$me.XXXXXX")" 73 74# list interesting files in $inc_dir. 75cd "$inc_dir" 76inc_dir="$(pwd -P)" 77find . -type f -name '*.h' -print0 | 78 xargs -r0 grep -l "$r_value" -- > "$tmpdir"/headers1.list || 79 exit 0 80cd - > /dev/null 81sed 's|^\./\(uapi/\)\?||' < "$tmpdir"/headers1.list > "$tmpdir"/headers.list 82LC_COLLATE=C sort -u -o "$tmpdir"/headers.list "$tmpdir"/headers.list 83 84msg "processing $(wc -l < "$tmpdir"/headers.list) header files from $inc_dir" 85failed=0 86 87CC="${CC:-gcc}" 88CPP="${CPP:-cpp}" 89CPPFLAGS="${CPPFLAGS-} -D__EXPORTED_HEADERS__" 90CFLAGS="${CFLAGS:--Wall -O2} -D__EXPORTED_HEADERS__" 91LDFLAGS="${LDFLAGS-}" 92INCLUDES="-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> 97for 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__ 104done 105 106INCLUDES="-I$tmpdir $INCLUDES" 107 108process_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 141typedef signed char s8; 142typedef unsigned char u8; 143typedef signed short s16; 144typedef unsigned short u16; 145typedef signed int s32; 146typedef unsigned int u32; 147typedef signed long long s64; 148typedef 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 159void print_ioctlent(const char *, const char *, unsigned short, unsigned short, unsigned short, unsigned short); 160 161int main(void) 162{ 163 164#include "defs.h" 165 166return 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__' 259struct usbdevfs_ctrltransfer32 { __u32 unused[4]; }; 260struct usbdevfs_bulktransfer32 { __u32 unused[4]; }; 261struct usbdevfs_disconnectsignal32 { __u32 unused[2]; }; 262struct usbdevfs_urb32 { __u8 unused[42]; }; 263struct 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> 272struct 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__' 290typedef uint32_t grant_ref_t; 291typedef 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 ' 340s/^[[:space:]]*\([A-Z][A-Z_0-9]*\)[[:space:]]*=[[:space:]]*_\(IO\|IOW\|IOR\|IOWR\|IOC\)[[:space:]]*(/#define \1 _\2(/ 341s/^\(#define .*)\),$/\1/ 342s/^\(#define .*,\)$/\1 \\/ 343s/^\([[: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 426while read f; do 427 (process_file "$f" < /dev/null) 428 [ $? -eq 0 ] || { 429 msg "$f: failed to process" 430 failed=$((1 + $failed)) 431 } 432done < "$tmpdir"/headers.list 433 434[ $failed -eq 0 ] || 435 msg "failed to process $failed file(s)" 436