tcpdump mailing list archives

Re: AC_LBL_FIXINCLUDES does not make it into configure


From: Guy Harris via tcpdump-workers <tcpdump-workers () lists tcpdump org>
Date: Tue, 17 Jan 2023 18:35:58 -0800

--- Begin Message --- From: Guy Harris <gharris () sonic net>
Date: Tue, 17 Jan 2023 18:35:58 -0800
On Jan 17, 2023, at 3:13 PM, Denis Ovsienko via tcpdump-workers <tcpdump-workers () lists tcpdump org> wrote:

In tcpdump commit cee234c there are three messages changed in
aclocal.m4, but only two messages changed in the resulting configure
script.  After a brief look it is clear that it is the third message
(the one in AC_LBL_FIXINCLUDES) that does not make it to the script,
but I don't understand whether this means a bug or just some dead code.

AC_LBL_FIXINCLUDES is defined in aclocal.m4 for tcpdump, but isn't used in configure.ac for tcpdump.

This appears to date back to tcpdump 3.4 (the last LBL release).

So that code is, for tcpdump, not only merely dead, it's really most sincerely dead.

I think aclocal.m4 may have started out as a library of LBL autoconf macros; they may have copied them to both the 
tcpdump and libpcap releases, bringing along macros not used by both packages (maybe some not used by either package).  
They were identical in libpcap 0.4 and tcpdump 3.4.

They've since moved apart; given that it has not been used by tcpdump at least since 3.4, we can probably just remove 
it from tcpdump's aclocal.m4.

And perhaps we could remove it, and the call to it, from libpcap's configure script as well, as it may only be needed 
if you're configuring libpcap to build on and for SunOS 3 and SunOS 4.  If you're curious what AC_LBL_FIXINCLUDES is 
for, and why most platforms don't need it, continue reading.

What AC_LBL_FIXINCLUDES does is "if using gcc, make sure we have ANSI ioctl definitions".

Back when ANSI C compilers were rare, system header files back in the mid-to-late 1980's had to work with pre-C89 
compilers.

In V7 UNIX, ioctl codes were of the form (('c' << 8) | code), where 'c' was an octet value, normally a printable 
character, indicating the type of object (typically, a device) for which the ioctl was intended, and code was a 
numerical value specifying a particular code.  It was up to the individual ioctl call in the kernel to move the 
argument from or to userland.  V7 was originally on a PDP-11, where an int is 16 bits, and an ioctl code was an int, so 
that ate up all 16 bits.

4.2BSD, which ran on VAXes where an int is 32 bits, expanded the ioctl codes to include an indication of whether the 
argument should be copied into the kernel, copied out of the kernel, copied into the kernel and copied back out of the 
kernel, or left up to the ioctl handler to process, and the size of the argument in bytes.  They introduced some macros:

        _IO() - for ioctls where the kernel does no copying;

        _IOR() - for ioctls where the kernel copies data out ("R" for "read", i.e., the kernel provides data to 
userland);

        _IOW() - for ioctls where the kernel copies data in ("W" for "write", i.e., data is provide to the kernel by 
userland);

        _IOWR() - for ioctls where the kernel copies data in and back out.

The 4.2BSD definitions for those are:

        #define _IO(x,y)        (IOC_VOID|('x'<<8)|y)
        #define _IOR(x,y,t)     (IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|('x'<<8)|y)
        #define _IOW(x,y,t)     (IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|('x'<<8)|y)
        /* this should be _IORW, but stdio got there first */
        #define _IOWR(x,y,t)    (IOC_INOUT|((sizeof(t)&IOCPARM_MASK)<<16)|('x'<<8)|y)

This relied on x, within 'x', being expanded by the C preprocessor; you'd write an ioctl as something such as

        #define TIOCGETD        _IOR(t, 0, int)         /* get line discipline */

As I remember, ANSI C indicated that it should *not* be expanded, which broke that; the current definitions, in systems 
that use BSD-style ioctls, are something such as the 4.4BSD definitions:

        #define _IOC(inout,group,num,len) \
                (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
        #define _IO(g,n)        _IOC(IOC_VOID,  (g), (n), 0)
        #define _IOR(g,n,t)     _IOC(IOC_OUT,   (g), (n), sizeof(t))
        #define _IOW(g,n,t)     _IOC(IOC_IN,    (g), (n), sizeof(t))
        /* this should be _IORW, but stdio got there first */
        #define _IOWR(g,n,t)    _IOC(IOC_INOUT, (g), (n), sizeof(t))

and you'd write an ioctl as something such as

        #define TIOCGETD _IOR('t', 26, int) /* get line discipline */ 

(yes, they changed the code).

This meant that an ANSI C compiler for a UN*X with BSD-style ioctls defined in a non-ANSI-compatible style couldn't 
rely on the system include files' definitions of ioctl - it would have to have its own header files.

GCC handled this with a script called fixincludes, which tweaked non-ANSI-C-compatible things in header files.  The 
purpose of AC_LBL_FIXINCLUDES is to handle pre-ANSI UN*Xes with GCC, to make sure that the compile is getting the 
fixincludes-modified header files.  It tests for _IO not handling a first argument that's a C character constant rather 
than a character to be stuffed into a C character constant.

This was not an issue for tcpdump 3.4, as it didn't do any ioctls.

It was an issue for libpcap 0.4, as, on SunOS 3 and 4 without BPF, it used native packet capture mechanisms, which 
involved making ioctls.

I suspect SunOS 3 and 4 are the only UN*Xes with non-ANSI headers for which we nominally have support.  Were we to drop 
support, we could get rid of pcap-nit.c and pcap-snit.c, tests for NIT and STREAMS NIT in the configure file, and kill 
off AC_LBL_FIXINCLUDES in libpcap as well.

(Today's lesson in Ancient UN*X History is brought to you by the Old Men Yelling At Clouds Foundation.  No, not *that* 
type of cloud.)

--- End Message ---
_______________________________________________
tcpdump-workers mailing list
tcpdump-workers () lists tcpdump org
https://lists.sandelman.ca/mailman/listinfo/tcpdump-workers

Current thread: