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