2 # Copyright (c) 2015 Dmitry V. Levin <ldv@altlinux.org>
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
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.
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.
29 # This script processes header files containing ioctl command definitions in
30 # symbolic form, assuming that these definitions match the following regular
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}"
42 printf >&2 '%s\n' "$me: $*"
47 1) inc_dir="$1"; shift
49 2) inc_dir="$1"; shift
52 *) echo >&2 "usage: $me include-directory [prefix]"
58 prefix="${prefix%%/}/"
69 trap 'cleanup $?' EXIT
70 trap 'cleanup 1' HUP PIPE INT QUIT TERM
71 tmpdir="$(mktemp -dt "$me.XXXXXX")"
73 # list interesting files in $inc_dir.
76 find . -type f -name '*.h' -print0 |
77 xargs -r0 grep -l "$r_value" -- > "$tmpdir"/headers1.list ||
80 sed 's|^\./\(uapi/\)\?||' < "$tmpdir"/headers1.list > "$tmpdir"/headers.list
81 sort -u -o "$tmpdir"/headers.list "$tmpdir"/headers.list
83 msg "processing $(wc -l < "$tmpdir"/headers.list) header files from $inc_dir"
88 CPPFLAGS="${CPPFLAGS-} -D__EXPORTED_HEADERS__"
89 CFLAGS="${CFLAGS:--Wall -O2} -D__EXPORTED_HEADERS__"
91 INCLUDES="-I$inc_dir/uapi -I$inc_dir ${INCLUDES-}"
93 $CC $INCLUDES $CFLAGS -c -o "$tmpdir"/print_ioctlent.o "${0%/*}"/print_ioctlent.c
95 # Hook onto <asm-generic/ioctl.h> and <asm/ioctl.h>
96 for d in asm-generic asm; do
98 cat > "$tmpdir/$d"/ioctl.h <<__EOF__
99 #include_next <$d/ioctl.h>
101 #define _IOC(dir,type,nr,size) dir, type, nr, size
105 INCLUDES="-I$tmpdir $INCLUDES"
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>
119 #include <sys/types.h>
120 #include <sys/socket.h>
125 # define NULL ((void*)0)
134 # define __noreturn __attribute__((noreturn))
137 # define __packed __attribute__((packed))
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;
151 #include <asm/bitsperlong.h>
152 #ifndef BITS_PER_LONG
153 # define BITS_PER_LONG __BITS_PER_LONG
158 void print_ioctlent(const char *, const char *, unsigned short, unsigned short, unsigned short, unsigned short);
169 # Soft workarounds for some processed files. Fragile.
172 echo '#include <asm/dasd.h>'
176 #include <asm/termios.h>
177 #include <linux/serial.h>
181 echo '#include <drm/drm.h>'
185 #include <linux/fb.h>
191 echo '#include <linux/atm.h>'
194 echo 'typedef u32 compat_ulong_t;'
198 struct btrfs_ioctl_defrag_range_args { __u32 unused[12]; };
199 #define BTRFS_LABEL_SIZE 256
202 *linux/coda.h|*android_alarm.h)
204 #ifndef _LINUX_TIME_H
205 # define _LINUX_TIME_H
207 #ifndef _UAPI_LINUX_TIME_H
208 # define _UAPI_LINUX_TIME_H
212 *linux/fs.h|*linux/ncp_fs.h)
214 #include <linux/blktrace_api.h>
215 #include <linux/fiemap.h>
220 #include <linux/if.h>
221 #include <linux/in.h>
222 #include <linux/in6.h>
225 *linux/if_tun.h|*linux/ppp-ioctl.h)
226 echo '#include <linux/filter.h>'
228 *linux/isdn_ppp.h|*linux/gsmmux.h)
229 echo '#include <linux/if.h>'
232 echo 'typedef struct poll_table_struct poll_table;'
234 *linux/ivtvfb.h|*linux/meye.h|*media/*.h)
235 echo '#include <linux/videodev2.h>'
239 #if defined __x86_64__ || defined __i386__
240 struct kvm_create_spapr_tce { __u32 unused[3]; };
241 struct kvm_allocate_rma { __u32 unused[2]; };
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]; };
249 echo '#include <linux/atmioc.h>'
251 *linux/usbdevice_fs.h)
253 struct usbdevfs_ctrltransfer32 { __u32 unused[4]; };
254 struct usbdevfs_bulktransfer32 { __u32 unused[4]; };
255 struct usbdevfs_disconnectsignal32 { __u32 unused[2]; };
256 struct usbdevfs_urb32 { __u8 unused[42]; };
257 struct usbdevfs_ioctl32 { __u32 unused[3]; };
261 echo 'typedef __u32 kuid_t;'
265 #include <sound/asound.h>
266 struct snd_seq_queue_owner { __u32 unused[0]; };
271 #include <sound/asound.h>
272 #ifndef DECLARE_BITMAP
273 # define DIV_ROUND_UP(x,y) (((x) + ((y) - 1)) / (y))
274 # define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, 8 * sizeof(long))
275 # define DECLARE_BITMAP(name,bits) unsigned long name[BITS_TO_LONGS(bits)]
280 echo 'struct fb_info;'
283 return 0 # false positives
286 return 0 # too much work to make it compileable
288 esac > "$tmpdir"/fixes.h
290 cat > "$tmpdir"/header.in <<__EOF__
291 #include <asm/bitsperlong.h>
292 #ifndef BITS_PER_LONG
293 # define BITS_PER_LONG __BITS_PER_LONG
298 if [ -f "$inc_dir/uapi/$f" ]; then
300 elif [ -f "$inc_dir/$f" ]; then
303 msg "$f: file not found"
307 [ -n "${f##*/*}" ] ||
308 mkdir -p "$tmpdir/${f%/*}"
309 # Hard workarounds for some processed files. Very fragile.
311 *acpi/*|*linux/i2o.h|*media/exynos-fimc.h|*media/v4l2-subdev.h|*net/bluetooth/*)
313 grep "${r_define}${r_cmd_name}" < "$s" > "$tmpdir/$f"
316 # Convert enums to macros.
317 sed '/^enum binder/,/^};/d' < "$s" > "$tmpdir/$f"
318 sed -n '/^enum binder/,/^};/ s/^[[:space:]].*/&/p' < "$s" |
320 s/^[[:space:]]*\([A-Z][A-Z_0-9]*\)[[:space:]]*=[[:space:]]*_\(IO\|IOW\|IOR\|IOWR\|IOC\)[[:space:]]*(/#define \1 _\2(/
321 s/^\(#define .*)\),$/\1/
322 s/^\(#define .*,\)$/\1 \\/
323 s/^\([[:space:]]\+[^),]\+)\),$/\1/' >> "$tmpdir/$f"
326 # Filter out the code that references unknown types.
327 sed '/drm_r128_clear2_t/d' < "$s" > "$tmpdir/$f"
330 # Filter out the code that references unknown types.
331 sed '/^struct sis_file_private/,/^}/d' < "$s" > "$tmpdir/$f"
334 # Create the file it attempts to include.
335 touch "$tmpdir/via_drmclient.h"
336 # Filter out the code that references unknown types.
337 sed '/^struct via_file_private/,/^}/d' < "$s" > "$tmpdir/$f"
339 *linux/vmw_vmci_defs.h)
340 # Fetch ioctl macros only.
341 grep "${r_define}I" < "$s" > "$tmpdir/$f"
343 *media/v4l2-common.h)
344 # Fetch one piece of code containing ioctls definitions.
345 sed -n '/ remaining ioctls/,/ ---/p' < "$s" > "$tmpdir/$f"
348 # Create the file it attempts to include.
349 touch "$tmpdir/asm/bug.h"
351 openpromio.h|*/openpromio.h|fbio.h|*/fbio.h)
352 # Create the file it attempts to include.
353 mkdir -p "$tmpdir/linux"
354 touch "$tmpdir/linux/compiler.h"
356 if [ -f "$tmpdir/$f" ]; then
360 # This may fail if the file includes unavailable headers.
361 # In case of success it outputs both the #define directives
362 # and the result of preprocessing.
363 $CPP $CPPFLAGS -dD $INCLUDES < "$tmpdir"/header.in > "$tmpdir"/header.out
365 # Need to exclude ioctl commands defined elsewhere.
366 local_defines='^[[:space:]]*#[[:space:]]*define[[:space:]]\+\('"$r_cmd_name"'\)[[:space:]]'
367 sed -n 's/'"$local_defines"'.*/\1\\/p' "$s" > "$tmpdir"/local_names
368 r_local_names="$(tr '\n' '|' < "$tmpdir"/local_names)"
369 r_local_names="${r_local_names%%|}"
370 r_local_names="${r_local_names%%\\}"
372 # Keep this in sync with $regexp by replacing $r_cmd_name with $r_local_names.
373 defs_regexp="${r_define}\($r_local_names\)${r_value}"
375 qf="$(echo "$prefix$f" | sed 's/[&\/]/\\&/g')"
376 # This outputs lines in the following format:
377 # print_ioctlent("filename.h", "IOCTL_CMD_NAME", IOCTL_CMD_NAME);
378 sed -n 's/'"$defs_regexp"'.*/print_ioctlent("'"$qf"'", "\1", \1);/p' \
379 < "$tmpdir"/header.out > "$tmpdir"/defs.h
381 # If something is wrong with the file, this will fail.
382 $CC $INCLUDES $CFLAGS -c -o "$tmpdir"/printents.o "$tmpdir"/printents.c
383 $CC $LDFLAGS -o "$tmpdir"/print_ioctlents \
384 "$tmpdir"/printents.o "$tmpdir"/print_ioctlent.o
385 "$tmpdir"/print_ioctlents > "$tmpdir"/ioctlents
386 cat "$tmpdir"/ioctlents
387 msg "$f: fetched $(grep -c '^{' "$tmpdir"/ioctlents) ioctl entries"
391 (process_file "$f" < /dev/null)
393 msg "$f: failed to process"
394 failed=$((1 + $failed))
396 done < "$tmpdir"/headers.list
399 msg "failed to process $failed file(s)"