--- Begin Message ---
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 

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 

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)     
        #define _IOW(x,y,t)     
        /* this should be _IORW, but stdio got there first */
        #define _IOWR(x,y,t)    

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

Reply via email to