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 39me="${0##*/}" 40msg() 41{ 42 printf >&2 '%s\n' "$me: $*" 43} 44 45prefix= 46case $# 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 ;; 55esac 56 57[ -z "$prefix" ] || 58 prefix="${prefix%%/}/" 59 60tmpdir= 61cleanup() 62{ 63 trap - EXIT 64 [ -z "$tmpdir" ] || 65 rm -rf -- "$tmpdir" 66 exit "$@" 67} 68 69trap 'cleanup $?' EXIT 70trap 'cleanup 1' HUP PIPE INT QUIT TERM 71tmpdir="$(mktemp -dt "$me.XXXXXX")" 72 73# list interesting files in $inc_dir. 74cd "$inc_dir" 75inc_dir="$(pwd -P)" 76find . -type f -name '*.h' -print0 | 77 xargs -r0 grep -l "$r_value" -- > "$tmpdir"/headers1.list || 78 exit 0 79cd - > /dev/null 80sed 's|^\./\(uapi/\)\?||' < "$tmpdir"/headers1.list > "$tmpdir"/headers.list 81LC_COLLATE=C sort -u -o "$tmpdir"/headers.list "$tmpdir"/headers.list 82 83msg "processing $(wc -l < "$tmpdir"/headers.list) header files from $inc_dir" 84failed=0 85 86CC="${CC:-gcc}" 87CPP="${CPP:-cpp}" 88CPPFLAGS="${CPPFLAGS-} -D__EXPORTED_HEADERS__" 89CFLAGS="${CFLAGS:--Wall -O2} -D__EXPORTED_HEADERS__" 90LDFLAGS="${LDFLAGS-}" 91INCLUDES="-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> 96for 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__ 103done 104 105INCLUDES="-I$tmpdir $INCLUDES" 106 107process_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 140typedef signed char s8; 141typedef unsigned char u8; 142typedef signed short s16; 143typedef unsigned short u16; 144typedef signed int s32; 145typedef unsigned int u32; 146typedef signed long long s64; 147typedef 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 158void print_ioctlent(const char *, const char *, unsigned short, unsigned short, unsigned short, unsigned short); 159 160int main(void) 161{ 162 163#include "defs.h" 164 165return 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__' 198struct 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__ 240struct kvm_allocate_rma { __u32 unused[2]; }; 241struct kvm_create_spapr_tce { __u32 unused[3]; }; 242struct kvm_get_htab_fd { __u32 unused[8]; }; 243struct kvm_rtas_token_args { __u8 unused[128]; }; 244struct kvm_vcpu_init { __u32 unused[8]; }; 245#elif defined __arm64__ || defined __arm__ 246struct kvm_allocate_rma { __u32 unused[2]; }; 247struct kvm_cpuid { __u32 unused[2]; }; 248struct kvm_cpuid2 { __u32 unused[2]; }; 249struct kvm_create_spapr_tce { __u32 unused[3]; }; 250struct kvm_debugregs { __u32 unused[32]; }; 251struct kvm_get_htab_fd { __u32 unused[8]; }; 252struct kvm_lapic_state { __u32 unused[256]; }; 253struct kvm_memory_alias { __u32 unused[8]; }; 254struct kvm_msr_list { __u32 unused[1]; }; 255struct kvm_msrs { __u32 unused[2]; }; 256struct kvm_pit_state { __u32 unused[18]; }; 257struct kvm_pit_state2 { __u32 unused[28]; }; 258struct kvm_rtas_token_args { __u32 unused[128]; }; 259struct kvm_vcpu_events { __u32 unused[16]; }; 260struct kvm_x86_mce { __u32 unused[16]; }; 261struct kvm_xcrs { __u32 unused[98]; }; 262struct kvm_xen_hvm_config { __u32 unused[14]; }; 263struct 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__' 272struct usbdevfs_ctrltransfer32 { __u32 unused[4]; }; 273struct usbdevfs_bulktransfer32 { __u32 unused[4]; }; 274struct usbdevfs_disconnectsignal32 { __u32 unused[2]; }; 275struct usbdevfs_urb32 { __u8 unused[42]; }; 276struct 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> 285struct 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 ' 339s/^[[:space:]]*\([A-Z][A-Z_0-9]*\)[[:space:]]*=[[:space:]]*_\(IO\|IOW\|IOR\|IOWR\|IOC\)[[:space:]]*(/#define \1 _\2(/ 340s/^\(#define .*)\),$/\1/ 341s/^\(#define .*,\)$/\1 \\/ 342s/^\([[: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 409while read f; do 410 (process_file "$f" < /dev/null) 411 [ $? -eq 0 ] || { 412 msg "$f: failed to process" 413 failed=$((1 + $failed)) 414 } 415done < "$tmpdir"/headers.list 416 417[ $failed -eq 0 ] || 418 msg "failed to process $failed file(s)" 419