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