diff --git a/CHANGES b/CHANGES index bffd0ae..666b962 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,7 @@ $Id$ Added support for token ring networks Token ring network direction determination Martin Garton +Added autoconf/automake build system 0.10 29/10/02 diff --git a/INSTALL b/INSTALL index b6e20f7..d24cdd0 100644 --- a/INSTALL +++ b/INSTALL @@ -1,13 +1,16 @@ Installation instructions for iftop $Id$ -1. Modify any settings at the top of the Makefile. Look in particular at PREFIX - and MANDIR. -2. Compile by typing make. +iftop is now autoconf/automake-enabled. You should be able to build it on +common platforms by typing `./configure && make'. -3. Install by typing make install. You will probably want to do this step as - root. +There is one gotcha, however, which is that some systems, such as FreeBSD, +lack a working implementation of the gethostbyaddr_r(3) C library function. On +such systems, you may want to use the --with-resolver=ares configure option to +build a version of iftop which uses the ARES asynchronous DNS library for name +resolution. An alternative is to use --with-resolver=netdb_1thread, which will +make iftop run only one name resolution thread. This is not recommended. -You can also use make uninstall to remove iftop and its manual page. +For historical interest, the old iftop makefile is included in Makefile.OLD. diff --git a/Makefile b/Makefile.OLD similarity index 84% rename from Makefile rename to Makefile.OLD index a6ada50..2855d1c 100644 --- a/Makefile +++ b/Makefile.OLD @@ -11,7 +11,7 @@ VERSION = 0.11pre1 #CC = gcc # Give the location of pcap.h here: -CFLAGS += -I/usr/include/pcap +CFLAGS += -I/usr/include/pcap -g # CFLAGS += -I/usr/pkg/include # CFLAGS += -pg -a @@ -20,6 +20,11 @@ CFLAGS += -I/usr/include/pcap # LDFLAGS += -L/usr/local/lib # LDFLAGS += -pg -a +# Do you want to use curses or ncurses? Probably ncurses, unless curses +# is ncurses on your machine. +CURSES = ncurses +#CURSES = curses + # # Name resolution. Sensible systems have gethostbyaddr_r, which is reentrant # and can be called from several threads of a multithreaded program. Other @@ -39,6 +44,12 @@ CFLAGS += -DUSE_GETHOSTBYADDR_R #CFLAGS += -DUSE_LIBRESOLV #CFLAGS += -DUSE_ARES +# +# On some machines, gethostbyaddr_r returns int; on others, struct hostent*. +# Comment out this line if you are using one of the latter. +# +#CFLAGS += -DGETHOSTBYADD_R_RETURNS_INT + # # Uncomment if you are using libresolv. # @@ -52,6 +63,11 @@ CFLAGS += -DUSE_GETHOSTBYADDR_R #CFLAGS += -I/software/include #LDFLAGS += -L/software/lib +# +# Solaris needs a library to make sockets go and lacks inet_aton. +# +LDLIBS += -lsocket -lnsl +CFLAGS += -DFAKE_INET_ATON # PREFIX specifies the base directory for the installation. PREFIX = /usr/local @@ -66,9 +82,8 @@ MANDIR = man # You shouldn't need to change anything below this point. CFLAGS += -g -Wall "-DIFTOP_VERSION=\"$(VERSION)\"" -LDFLAGS += -g -pthread -LDLIBS += -lpcap -lcurses -lm - +LDFLAGS += -g #-pthread +LDLIBS += -lpcap -l$(CURSES) -lm -lpthread SRCS = iftop.c addr_hash.c hash.c ns_hash.c resolver.c ui.c util.c sorted_list.c\ options.c serv_hash.c threadprof.c edline.c screenfilter.c @@ -83,6 +98,9 @@ OBJS = $(SRCS:.c=.o) iftop: $(OBJS) Makefile $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS) +integers.h: integers + ./integers + install: iftop install -D iftop $(PREFIX)/$(BINDIR)/iftop install -D iftop.8 $(PREFIX)/$(MANDIR)/man8/iftop.8 diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..8783899 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,40 @@ +# +# Makefile.am: +# Automake file for iftop. +# +# I don't understand this stuff, so I just stole it from the tpop3d +# distribution. That means that, really, Mark Longair should take credit for +# it. +# -- Chris Lightfoot +# +# $Id$ +# + +sbin_PROGRAMS = iftop + +iftop_SOURCES = addr_hash.c edline.c hash.c iftop.c ns_hash.c \ + options.c resolver.c screenfilter.c serv_hash.c \ + sorted_list.c threadprof.c ui.c util.c + +noinst_HEADERS = addr_hash.h ether.h ethertype.h extract.h hash.h iftop.h \ + integers.h ip.h llc.h ns_hash.h options.h resolver.h \ + screenfilter.h serv_hash.h sll.h sorted_list.h tcp.h \ + threadprof.h token.h ui.h + +man_MANS = iftop.8 + +SUBDIRS = config + +iftop.cat: iftop.8 + (echo -e ".pl 1100i" ; cat iftop.8 ; echo ".pl \n(nlu+10") | groff -Tascii -man > iftop.cat + +## These need to be distributed along with configure: + +EXTRA_DIST = bootstrap README CHANGES COPYING INSTALL TODO Makefile.OLD \ + $(man_MANS) iftop.cat + +MAINTERCLEANFILES = Makefile.in aclocal.m4 configure configuration.h.in \ + stamp-h.in + +ACLOCAL = aclocal -I @ac_aux_dir@ + diff --git a/README b/README index f5c2118..bb5e4e3 100644 --- a/README +++ b/README @@ -21,5 +21,13 @@ in order to compile iftop. FreeBSD 4.7: This version of FreeBSD lacks a proper gethostbyaddr_r function. You should -choose an alternative name resolution technique; see comments in the Makefile. -We recommend using ares (-DUSE_ARES). +choose an alternative name resolution technique using the --with-resolver=... +option to configure. + +Solaris: + +On Solaris, libpcap does not capture outgoing packets unless it is run on an +interface in promiscuous mode. Therefore, you will need to use the -p option +to iftop to get sensible results. Cf. + http://www.tcpdump.org/lists/workers/2002/02/msg00010.html + diff --git a/TODO b/TODO index 073d7f4..446c5b3 100644 --- a/TODO +++ b/TODO @@ -7,8 +7,6 @@ $Id$ * Config file. -* Find someone gullible to sort out autoconf. - * Which average to use for the bar graph? Show several and peaks? Colours? * Single keypress firewalling of troublesome connections, a la top(1)'s K diff --git a/bootstrap b/bootstrap new file mode 100755 index 0000000..4bfa59c --- /dev/null +++ b/bootstrap @@ -0,0 +1,13 @@ +#!/bin/sh +# +# bootstrap: +# Build the configure script from the .in files. +# +# $Id$ +# +set -x +aclocal -I config +# libtoolize --force --copy +autoheader +automake --foreign --add-missing --copy +autoconf diff --git a/config/Makefile.am b/config/Makefile.am new file mode 100644 index 0000000..bd0596f --- /dev/null +++ b/config/Makefile.am @@ -0,0 +1,18 @@ +# +# config/Makefile.am: +# Automake file for the extra config droppings. +# +# $Id$ +# + +EXTRA_DIST = hostentp_ghba_r.c int_ghba_r.c pthread.c + +AUX_DIST = config.guess \ + config.sub \ + install-sh \ + ltconfig \ + ltmain.sh \ + missing \ + mkinstalldirs + +MAINTERCLEANFILES = $(AUX_DIST) diff --git a/config/hostentp_ghba_r.c b/config/hostentp_ghba_r.c new file mode 100644 index 0000000..7c6cef2 --- /dev/null +++ b/config/hostentp_ghba_r.c @@ -0,0 +1,39 @@ +/* + * hostentp_ghba_r.c: + * Test program to see whether gethostbyaddr_r takes 7 arguments and returns + * struct hostent*. + */ + +static const char rcsid[] = "$Id$"; + +#include + +#include +#include +#include +#include +#include + +int main(void) { + struct in_addr localhost; + struct hostent hostbuf, *hp; + char *buf; + int herr; + size_t buflen = 1024; + + localhost.s_addr = htonl(INADDR_LOOPBACK); + buf = malloc(buflen); + while ((hp = gethostbyaddr_r((char*)&localhost, sizeof(struct in_addr), + AF_INET, &hostbuf, buf, buflen, &herr)) + == NULL + && errno == ERANGE) + buf = (char*)realloc(buf, buflen *= 2); + + /* We assume that the loopback address can always be resolved if + * gethostbyaddr_r is actually working. */ + if (hp == NULL) { + fprintf(stderr, "errno = %d, herr = %d\n", errno, herr); + return -1; + } else + return 0; +} diff --git a/config/int_ghba_r.c b/config/int_ghba_r.c new file mode 100644 index 0000000..7a3a3c1 --- /dev/null +++ b/config/int_ghba_r.c @@ -0,0 +1,38 @@ +/* + * int_ghba_r.c: + * Test program to see whether gethostbyaddr_r takes 8 arguments and returns + * int. + */ + +static const char rcsid[] = "$Id$"; + +#include + +#include +#include +#include +#include +#include + +int main(void) { + struct in_addr localhost; + struct hostent hostbuf, *hp; + char *buf; + int res, herr; + size_t buflen = 1024; + + localhost.s_addr = htonl(INADDR_LOOPBACK); + buf = malloc(buflen); + while ((res = gethostbyaddr_r((char*)&localhost, sizeof localhost, AF_INET, + &hostbuf, buf, buflen, &hp, &herr)) + == ERANGE) + buf = (char*)realloc(buf, buflen *= 2); + + /* We assume that the loopback address can always be resolved if + * gethostbyaddr_r is actually working. */ + if (res || hp == NULL) { + fprintf(stderr, "errno = %d, herr = %d, res = %d\n", errno, herr, res); + return -1; + } else + return 0; +} diff --git a/config/pthread.c b/config/pthread.c new file mode 100644 index 0000000..071e5ae --- /dev/null +++ b/config/pthread.c @@ -0,0 +1,62 @@ +/* + * pthread.c: + * Tiny test program to see whether POSIX threads work. + */ + +static const char rcsid[] = "$Id$"; + +#include + +#include +#include +#include +#include +#include + +static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static int return_value = -1; + +void *worker_thread(void *v) { + /* Record successful return and signal parent to wake up. */ + return_value = 0; + pthread_mutex_lock(&mtx); + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mtx); + while (1) + pause(); +} + +/* Start a thread, and have it set a variable to some other value, then signal + * a condition variable. If this doesn't happen within some set time, we assume + * that something's gone badly wrong and abort (for instance, the thread never + * got started). */ +int main(void) { + pthread_t thr; + int res; + struct timespec deadline = {0}; + if ((res = pthread_mutex_lock(&mtx)) != 0 + || (res = pthread_create(&thr, NULL, worker_thread, NULL)) != 0) { + fprintf(stderr, "%s\n", strerror(res)); + return -1; + } + + /* Thread should now be running; we should wait on the condition + * variable. */ + do + deadline.tv_sec = 2 + time(NULL); + while ((res = pthread_cond_timedwait(&cond, &mtx, &deadline)) == EINTR); + + if (res != 0) { + fprintf(stderr, "%s\n", strerror(res)); + return -1; + } + + if ((res = pthread_cancel(thr)) != 0 + || (res = pthread_join(thr, NULL)) != 0) { + fprintf(stderr, "%s\n", strerror(res)); + return -1; + } + + return return_value; +} diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..e208efc --- /dev/null +++ b/configure.in @@ -0,0 +1,305 @@ +dnl +dnl configure.in: +dnl Autoconf input for iftop. +dnl +dnl I hate autoconf with a passion. It's an utter pain to write these bloody +dnl things and even once you have you find yourself testing for more and more +dnl special cases. But that's OK. Paul is going to maintain it :) +dnl -- Chris Lightfoot +dnl +dnl $Id$ +dnl + +dnl +dnl Boilerplate configuration +dnl + +AC_INIT(iftop.c) +AC_CONFIG_AUX_DIR(config) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE(iftop, "0.11pre1") + +AC_DEFINE_UNQUOTED(IFTOP_VERSION, "$VERSION", [The iftop version number]) + +dnl Make sure we have a C compiler.... +AC_PROG_CC +AC_HEADER_STDC + +dnl +dnl Options to configure. +dnl + +AC_ARG_WITH(resolver, + [ --with-resolver=TYPE Technique iftop should use for name resolution. Valid + options are netdb, netdb_1thread (for systems without + working gethostbyaddr_r), ares for the MIT ARES + asynchronous resolver library, or none if you don't + need any name resolution. + [default=netdb]], + [resolver=$withval], + [resolver=netdb]) + +dnl +dnl Fairly generic checks. +dnl + +dnl Checks for system headers. +AC_CHECK_HEADERS(sys/ioctl.h sys/time.h sys/sockio.h unistd.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_SIZE_T +AC_HEADER_TIME + +dnl Checks for library functions. +AC_CHECK_FUNCS(regcomp select strdup strerror strspn) + +AC_SEARCH_LIBS(socket, socket) +AC_SEARCH_LIBS(log, m) +AC_CHECK_FUNC(gethostbyname, , + [AC_CHECK_LIB(nsl, gethostbyname)] ) + +AC_SEARCH_LIBS(inet_aton, [-lsocket -lnsl]) +AC_SEARCH_LIBS(inet_pton, [-lsocket -lnsl]) +AC_CHECK_FUNCS(inet_aton inet_pton) + +dnl +dnl Find integers of known physical size. This is a pain in the arse because +dnl we can't use AC_CHECK_SIZEOF to find the original variables, since that +dnl function doesn't permit us to include a header file. Sigh. +dnl + +for type in u_int8_t u_int16_t u_int32_t ; do + AC_MSG_CHECKING([size of $type]) + defn="SIZEOF_"`echo $type | tr a-z A-Z` + AC_TRY_RUN([ +#include +#include +int main() { + $type dummy; + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof($1)); + exit(0); +} + ], [ + x=`cat conftestval` + eval "size_$type=$x" + AC_MSG_RESULT([$x]) + ], [ + eval "size_$type=0" + AC_MSG_RESULT([unknown type]) + ]) +done + +dnl Groan. Have to do things this way so that autoheader can do its thing.... +AC_DEFINE_UNQUOTED(SIZEOF_U_INT8_T, [$size_u_int8_t], [size of u_int8_t]) +AC_DEFINE_UNQUOTED(SIZEOF_U_INT16_T, [$size_u_int16_t], [size of u_int16_t]) +AC_DEFINE_UNQUOTED(SIZEOF_U_INT32_T, [$size_u_int32_t], [size of u_int32_t]) + +dnl If we already have these types, don't piss about any more.... +if test $size_u_int8_t != 1 -o $size_u_int16_t != 2 -o $size_u_int32_t != 4 ; then + do_int_types=1 + AC_CHECK_HEADERS( + [stdint.h dnl C99 + sys/inttypes.h], dnl Solaris + [do_int_types=0; break]) + + if test $do_int_types = 1 ; then + dnl No C99 int types, so figure them out from basic types. + AC_CHECK_SIZEOF(unsigned short int) + AC_CHECK_SIZEOF(unsigned int) + AC_CHECK_SIZEOF(unsigned long int) + else + dnl Just use the C99 ones. + AC_DEFINE(HAVE_C99_INTS, 1, [C99 fixed-width int types available]) + fi +fi + +dnl +dnl Name resolution. +dnl +dnl This is complicated because we need some sort of reentrant mechanism for +dnl name resolution. Naturally, UNIX vendors have come up with a variety of +dnl incompatible schemes for this, many of which don't work at all. +dnl + +dnl First, the default resolver, which uses getnameinfo or gethostbyaddr_r. If +dnl not available, we fall back to gethostbyaddr. We could fall back to ARES, +dnl but that's probably not available on typical machines. +if test x$resolver = xnetdb ; then + dnl Best possibility is getnameinfo. + use_getnameinfo=0 + AC_SEARCH_LIBS(getnameinfo, [-lnsl], [use_getnameinfo=1]) + + dnl XXX For the moment, don't use getnameinfo, since it isn't actually + dnl thread safe on, e.g., NetBSD. + use_getnameinfo=0 + + if test $use_getnameinfo = 1 ; then + dnl Done. + AC_DEFINE(USE_GETNAMEINFO, 1, [use getnameinfo for name resolution]) + else + dnl Now see if we can use gethostbyaddr_r. + AC_SEARCH_LIBS(gethostbyaddr_r, [-lnsl], , [resolver=netdb_1thread]) + + dnl Still want gethostbyaddr_r.... + if test x$resolver = xnetdb ; then + dnl Figure out whether we have glibc-style or Solaris-style + dnl gethostbyaddr_r (or neither...). + AC_MSG_CHECKING([how to call gethostbyaddr_r]); + + AC_TRY_RUN([`cat config/int_ghba_r.c`], [ + dnl 8-arg, int + AC_MSG_RESULT([8 args, int return]) + AC_DEFINE(GETHOSTBYADDR_R_RETURNS_INT, 1, + [8-argument gethostbyaddr_r returns int]) + ], [ + AC_TRY_RUN([`cat config/hostentp_ghba_r.c`], [ + dnl 7-arg, struct hostent* + AC_MSG_RESULT([7 args, struct hostent* return]) + AC_DEFINE(GETHOSTBYADDR_R_RETURNS_HOSTENT_P, 1, + [7-argument gethostbyaddr_r returns struct hostent*]) + ], [ + dnl neither + AC_MSG_RESULT([no idea; dropping back to gethostbyaddr]) + resolver=netdb_1thread + ]) + ]) + + dnl Found a gethostbyaddr_r we know how to use and which seems to + dnl work. + if test x$resolver = xnetdb ; then + AC_DEFINE(USE_GETHOSTBYADDR_R, 1, [use gethostbyaddr_r for name resolution]) + fi + fi + fi +fi + +dnl If we've been told to use ARES, then see if it's available. If it isn't, +dnl fall back to gethostbyaddr, since we can probably assume that if the +dnl machine had a working gethostbyaddr_r, the user wouldn't be pissing about +dnl with ARES. +if test x$resolver = xares ; then + dnl See if ares is to hand.... + AC_SEARCH_LIBS(ares_init, [-lares], [ + AC_DEFINE(USE_ARES, 1, [use ARES for name resolution]) + ], [ + dnl no ares + AC_MSG_RESULT([can't find ARES; dropping back to gethostbyaddr]) + resolver=netdb_1thread]) +fi + + +dnl Ugh. gethostbyaddr. +if test x$resolver = xnetdb_1thread ; then + AC_SEARCH_LIBS(gethostbyaddr, [-lnsl], , [ + AC_MSG_ERROR([not even gethostbyaddr is available + What sort of UNIX system is this, anyway?]) + ] + ) + + dnl Oh dear, just use gethostbyaddr; but whine about it + AC_MSG_WARN([using single-threaded resolver with gethostbyaddr + Consider obtaining ARES or a machine with a working gethostbyaddr_r.]) + + AC_DEFINE(USE_GETHOSTBYADDR, 1, [use gethostbyaddr for name resolution]) +fi + +dnl Otherwise, no resolver at all. Boo hoo. + + +dnl +dnl Ensure that the machine even has libpcap. We do this late, because libpcap +dnl calls netdb functions that might need libraries on some systems.... +dnl + +AC_CHECK_LIB(pcap, pcap_open_live, , [ + AC_MSG_ERROR([can't find libpcap + You're not going to get very far without libpcap.]) + ]) + +foundpcap=0 +AC_CHECK_HEADERS([pcap.h pcap/pcap.h], [ + foundpcap=1 + break + ]) + +if test $foundpcap = 0 ; then + AC_MSG_ERROR([can't find pcap.h + You're not going to get very far without libpcap.]) +fi + +dnl +dnl Curses. Really, we need ncurses or something similarly advanced, since +dnl we use the (apparently obscure) mvchgat function. Unfortunately, there's +dnl a solid chance that mvchgat is a macro, so we can't just use +dnl AC_SEARCH_LIBS.... +dnl + +AC_MSG_CHECKING([for a curses library containing mvchgat]) +oldLIBS=$LIBS +for curseslib in curses ncurses ; do + LIBS="$oldLIBS -l$curseslib" + AC_TRY_LINK([ +#include + ], [ + mvchgat(0, 0, 1, A_REVERSE, 0, NULL) + ], [ + foundcurseslib=$curseslib + break + ]) +done + +if test x$foundcurseslib = x ; then + AC_MSG_RESULT([none found]) + AC_MSG_ERROR([Curses! Foiled again! + (Can't find a curses library supporting mvchgat.) + Consider installing ncurses.]) +else + AC_MSG_RESULT([-l$foundcurseslib]) +fi + + +dnl +dnl POSIX threads. Different systems like different combinations of flags, +dnl libraries, etc. We use a test program to figure this stuff out. +dnl + +AC_MSG_CHECKING([how to compile a working program with POSIX threads]) +thrfail=1 +oldCFLAGS=$CFLAGS +oldLIBS=$LIBS +for flag in "" -mt -pthread -thread ; do + CFLAGS="$oldCFLAGS $flag" + for lib in "" -lpthread "-lpthread -lposix4" ; do + LIBS="$oldLIBS $lib" + AC_TRY_RUN([`cat config/pthread.c`], [ + foundthrlib=$lib + foundthrflag=$flag + thrfail=0 + break + ]) + done + if test $thrfail = 0 ; then + break + fi +done + +if test $thrfail = 1 ; then + AC_MSG_RESULT([no idea]) + AC_MSG_ERROR([can't figure out how to compile with POSIX threads + If your system actually supports POSIX threads, this means we've messed up.]) +else + AC_MSG_RESULT([$foundthrflag $foundthrlib]) +fi + +dnl +dnl Wahey! This might even work. +dnl + + +AC_SUBST(ac_aux_dir) + +AC_OUTPUT(Makefile config/Makefile) + diff --git a/edline.c b/edline.c index 55f0c31..96835fc 100644 --- a/edline.c +++ b/edline.c @@ -88,9 +88,9 @@ char *edline(int linenum, const char *prompt, const char *initial) { case 23: /* ^W */ for (i = pos; i > 0; --i) - if (!isspace(str[i])) break; + if (!isspace((int)str[i])) break; for (; i > 0; --i) - if (isspace(str[i])) break; + if (isspace((int)str[i])) break; if (i != pos) { memmove(str + i, str + pos, strlen(str + pos) + 1); pos = i; diff --git a/iftop.c b/iftop.c index d7bca4d..6c4129a 100644 --- a/iftop.c +++ b/iftop.c @@ -3,7 +3,15 @@ * */ -#include +#include "integers.h" + +#if defined(HAVE_PCAP_H) +# include +#elif defined(HAVE_PCAP_PCAP_H) +# include +#else +# error No pcap.h +#endif #include #include #include @@ -340,9 +348,9 @@ static void handle_eth_packet(unsigned char* args, const struct pcap_pkthdr* pkt { struct ether_header *eptr; eptr = (struct ether_header*)packet; - + tick(0); - + if(ntohs(eptr->ether_type) == ETHERTYPE_IP) { struct ip* iptr; int dir = -1; @@ -464,7 +472,7 @@ void packet_init() { /* packet_loop: * Worker function for packet capture thread. */ void packet_loop(void* ptr) { - pcap_loop(pd,0,(pcap_handler)packet_handler,NULL); + pcap_loop(pd,-1,(pcap_handler)packet_handler,NULL); } diff --git a/iftop.h b/iftop.h index cad1d95..d645108 100644 --- a/iftop.h +++ b/iftop.h @@ -6,6 +6,8 @@ #ifndef __IFTOP_H_ /* include guard */ #define __IFTOP_H_ +#include "config.h" + /* 60 / 3 */ #define HISTORY_LENGTH 20 #define RESOLUTION 2 @@ -34,11 +36,13 @@ void ui_init(void); void options_read(int argc, char **argv); -/* Make use of SIOCGIFHWADDR work on FreeBSD */ +/* Make use of SIOCGIFHWADDR work on FreeBSD and Solaris. */ #ifndef SIOCGIFHWADDR -#define SIOCGIFHWADDR SIOCGIFADDR -#define ifr_hwaddr ifr_addr +# ifdef HAVE_SYS_SOCKIO_H +# include /* Solaris and others?? */ +# endif +# define SIOCGIFHWADDR SIOCGIFADDR +# define ifr_hwaddr ifr_addr #endif - #endif /* __IFTOP_H_ */ diff --git a/integers.h b/integers.h new file mode 100644 index 0000000..f6171e4 --- /dev/null +++ b/integers.h @@ -0,0 +1,81 @@ +/* + * integers.h: + * This header file ensures that we have u_int_t types of the proper width, + * using a rather convoluted set of conditionals generated by configure. This + * is an almighty pain in the arse, and is completely irrelevant on most + * systems which already define this stuff. + * + * $Id$ + * + */ + +#ifndef __INTEGERS_H_ /* include guard */ +#define __INTEGERS_H_ + +#include +#include "config.h" + +#if SIZEOF_U_INT8_T != 1 || SIZEOF_U_INT16_T != 2 || SIZEOF_U_INT32_T != 4 + +# if defined(HAVE_C99_INTS) + + /* + * Use the C99 standard-width integers, defined in some appropriate + * header file. + */ + +# if defined(HAVE_STDINT_H) +# include +# elif defined(HAVE_SYS_INTTYPES_H) +# include +# endif + + /* Don't replace existing u_int_t types. */ +# if SIZEOF_U_INT8_T != 1 + typedef uint8_t u_int8_t; +# endif + +# if SIZEOF_U_INT16_T != 2 + typedef uint16_t u_int16_t; +# endif + +# if SIZEOF_U_INT32_T != 4 + typedef uint32_t u_int32_t; +# endif + +# elif (SIZEOF_UNSIGNED_SHORT_INT == 2 || SIZEOF_UNSIGNED_INT == 2) \ + && (SIZEOF_UNSIGNED_INT == 4 || SIZEOF_UNSIGNED_LONG_INT == 4) + + /* + * Use an appropriately-sized basic type. + */ + +# if SIZEOF_U_INT8_T != 1 + typedef unsigned char u_int8_t; /* By definition. */ +# endif + +# if SIZEOF_U_INT16_T != 2 +# if SIZEOF_UNSIGNED_SHORT_INT == 2 + typedef unsigned short int u_int16_t; +# elif SIZEOF_UNSIGNED_INT == 2 + typedef unsigned int u_int16_t; /* Not likely. */ +# endif +# endif + +# if SIZEOF_U_INT32_T != 4 +# if SIZEOF_UNSIGNED_INT == 4 + typedef unsigned int u_int32_t; +# elif SIZEOF_UNSIGNED_LONG_INT == 4 + typedef unsigned long int u_int32_t; +# endif +# endif + + /* Whew. */ + +# else +# error "Your C compiler seems to lack 16 and 32 bit unsigned integer types" +# endif + +#endif /* No existing u_int_t types. */ + +#endif /* __INTEGERS_H_ */ diff --git a/options.c b/options.c index 864e060..cd53838 100644 --- a/options.c +++ b/options.c @@ -4,6 +4,8 @@ * */ +#include + #include #include #include @@ -11,11 +13,17 @@ #include #include +#include +#include #include #include "iftop.h" #include "options.h" +#if !defined(HAVE_INET_ATON) && defined(HAVE_INET_PTON) +# define inet_aton(a, b) inet_pton(AF_INET, (a), (b)) +#endif + options_t options; char optstr[] = "+i:f:nN:hpbBP"; diff --git a/resolver.c b/resolver.c index 086bde5..faf8fd7 100644 --- a/resolver.c +++ b/resolver.c @@ -35,13 +35,37 @@ int tail; /* - * We have a choice of resolver methods. Real computers have gethostbyaddr_r, - * which is reentrant and therefore thread safe. Other machines don't, and so - * we can use non-reentrant gethostbyaddr and have only one resolver thread. - * Alternatively, we can use the MIT ares asynchronous DNS library to do this. + * We have a choice of resolver methods. Real computers have getnameinfo or + * gethostbyaddr_r, which are reentrant and therefore thread safe. Other + * machines don't, and so we can use non-reentrant gethostbyaddr and have only + * one resolver thread. Alternatively, we can use the MIT ares asynchronous + * DNS library to do this. */ -#if defined(USE_GETHOSTBYADDR_R) +#if defined(USE_GETNAMEINFO) +/** + * Implementation of do_resolve for platforms with getaddrinfo. + * + * This is a fairly sane function with a uniform interface which is even -- + * shock! -- standardised by POSIX and in RFC 2553. Unfortunately systems such + * as NetBSD break the RFC and implement it in a non-thread-safe fashion, so + * for the moment, the configure script won't try to use it. + */ +char *do_resolve(struct in_addr *addr) { + struct sockaddr_in sin = {0}; + char buf[NI_MAXHOST]; /* 1025 */ + int res; + sin.sin_family = AF_INET; + sin.sin_addr = *addr; + sin.sin_port = 0; + + if (getnameinfo((struct sockaddr*)&sin, sizeof sin, buf, sizeof buf, NULL, 0, NI_NAMEREQD) == 0) + return xstrdup(buf); + else + return NULL; +} + +#elif defined(USE_GETHOSTBYADDR_R) /** * Implementation of do_resolve for platforms with working gethostbyaddr_r * @@ -59,9 +83,20 @@ char* do_resolve(struct in_addr * addr) { /* Allocate buffer, remember to free it to avoid memory leakage. */ tmphstbuf = xmalloc (hstbuflen); - while ((res = gethostbyaddr_r ((char*)addr, sizeof(struct in_addr), AF_INET, - &hostbuf, tmphstbuf, hstbuflen, - &hp, &herr)) == ERANGE) { + /* Some machines have gethostbyaddr_r returning an integer error code; on + * others, it returns a struct hostent*. */ +#ifdef GETHOSTBYADDR_R_RETURNS_INT + while ((res = gethostbyaddr_r((char*)addr, sizeof(struct in_addr), AF_INET, + &hostbuf, tmphstbuf, hstbuflen, + &hp, &herr)) == ERANGE) +#else + /* ... also assume one fewer argument.... */ + while ((hp = gethostbyaddr_r((char*)addr, sizeof(struct in_addr), AF_INET, + &hostbuf, tmphstbuf, hstbuflen, &herr)) == NULL + && errno == ERANGE) +#endif + { + /* Enlarge the buffer. */ hstbuflen *= 2; tmphstbuf = realloc (tmphstbuf, hstbuflen); diff --git a/screenfilter.c b/screenfilter.c index a33431c..2d12ee2 100644 --- a/screenfilter.c +++ b/screenfilter.c @@ -6,6 +6,10 @@ * */ +#include "config.h" + +#ifdef HAVE_REGCOMP + #include #include #include @@ -54,3 +58,4 @@ int screen_filter_match(char *s) { } } +#endif /* HAVE_REGCOMP */ diff --git a/screenfilter.h b/screenfilter.h index c0c3192..d7189f7 100644 --- a/screenfilter.h +++ b/screenfilter.h @@ -10,7 +10,13 @@ #ifndef __SCREENFILTER_H_ /* include guard */ #define __SCREENFILTER_H_ +#include "config.h" + +#ifdef HAVE_REGCOMP + int screen_filter_set(char* s); int screen_filter_match(char* s); +#endif + #endif /* __SCREENFILTER_H_ */ diff --git a/ui.c b/ui.c index e793de2..3854026 100644 --- a/ui.c +++ b/ui.c @@ -3,6 +3,8 @@ * */ +#include + #include #include #include @@ -591,8 +593,10 @@ void ui_print() { if(showhelphint) { - mvaddstr(0, 0, helpmsg); - mvchgat(0, 0, strlen(helpmsg), A_REVERSE, 0, NULL); + mvaddstr(0, 0, " "); + mvaddstr(0, 1, helpmsg); + mvaddstr(0, 1 + strlen(helpmsg), " "); + mvchgat(0, 0, strlen(helpmsg) + 2, A_REVERSE, 0, NULL); } move(LINES - 1, COLS - 1); @@ -855,6 +859,7 @@ void ui_loop() { break; } case 'l': { +#ifdef HAVE_REGCOMP char *s; dontshowdisplay = 1; if ((s = edline(0, "Screen filter", options.screenfilter))) { @@ -864,6 +869,9 @@ void ui_loop() { } dontshowdisplay = 0; ui_print(); +#else + showhelp("Sorry, screen filters not supported on this platform") +#endif break; } case '!': {