[Iftop-users] Supporting cross-compilation

Tim Freeman tim at fungible.com
Sun, 12 Jun 2005 20:49:01 -0700


I was using my PC running Linux to compile iftop for my Linksys
WRT54GS router running Openwrt (which is an instance of Linux), and I
discovered that the "configure" script for iftop doesn't support
cross-compilation.  It insists on running experiments on the
local host.  I rearranged configure.in so the generated "configure"
script supports cross-compilation.

Some of the macros used in the old configure.in were deprecated
according to current autoconf documentation, so I substituted current
ones.

Here's a patch to configure.in.  The patch also adds a NO_SYSTEM
compiler flag that, when set, disables the "!" key that starts a
subshell.  This makes me more willing to run iftop as the login shell
of a passwordless account so the other users of my router can triage
some network performance problems without bugging me.

If you apply this patch to the distributed iftop tarball, you'll also
need to rerun autoheader, aclocal, automake, and autoconf before you
get a good "configure" script.  It's also possible to patch the
"configure" script directly, but that diff is large and meaningless
because it's updating a generated file.  I can generate a patch for
that if there's interest.

I would like to contribute this to the iftop source.  Let me know what
you decide to do with this.  I'll be happy to assign copyright if
that's an issue.

-- 
Tim Freeman               http://www.fungible.com           tim@fungible.com
Programmer/consultant in the Sunnyvale, CA area.       

diff -ru orig/iftop-0.16/configure.in ./configure.in
--- orig/iftop-0.16/configure.in	2004-02-28 10:53:37.000000000 -0800
+++ ./configure.in	2005-06-11 11:02:04.000000000 -0700
@@ -9,7 +9,15 @@
 dnl
 dnl $Id: configure.in,v 1.23 2004/02/28 18:53:37 pdw Exp $
 dnl
-
+dnl To regenerate everything from source, do:
+dnl    autoheader
+dnl    aclocal
+dnl    automake
+dnl    autoconf
+dnl Now you should have good sources to make into a tarball and distribute.
+dnl    ./configure     (perhaps with some arguments)
+dnl    make
+dnl Tested with Automake 1.4 and autoconf 2.59.
 dnl
 dnl Boilerplate configuration
 dnl
@@ -34,15 +42,23 @@
 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, forking for the REALLY
-                          SUCKY forking resolver, or none if you don't need any
-                          name resolution.
-                          [default=netdb]],
+    [  --with-resolver=TYPE    Technique iftop should use for name resolution.  
+                          Valid options are:
+			  netdb          use gethostbyaddr_r in multiple
+			                 threads.
+			  netdb_1thread  use gethostbyaddr_r and
+					 assume it is not reentrant.
+			  ares           use the MIT ARES asynchronous
+					 resolver library.
+			  forking        use the REALLY SUCKY forking resolver.
+			  guess          run experiments to guess a
+					 reasonable value.  Only works if you
+					 aren't cross-compiling.  This
+					 is the default.  guess will
+					 either select netdb or netdb_1thread.
+			  none           don't do name resolution.],
     [resolver=$withval],
-    [resolver=netdb])
+    [resolver=guess])
 
 AC_ARG_WITH(libpcap,
     [  --with-libpcap=WHERE    Where the libpcap packet-capture library is found.
@@ -151,7 +167,12 @@
 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 If we've been asked to guess, remember that fact in specified_resolver.
+dnl From this point on, resolver is our preferred resolver given the
+dnl experiments we've done so far, or "guess" if we have no idea.
+specified_resolver=$resolver
+if test x$specified_resolver = xguess ; then
     dnl Best possibility is getnameinfo.
     use_getnameinfo=0
     AC_SEARCH_LIBS(getnameinfo, [nsl], [use_getnameinfo=1])
@@ -164,75 +185,101 @@
         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, [nsl], , [resolver=forking])
+	dnl Best hope is netdb, which presently means gethostbyaddr_r.
+	resolver=netdb
+    fi
+fi
+
+if test x$resolver = xnetdb ; then
+    dnl Can use gethostbyaddr_r?
+    AC_SEARCH_LIBS(gethostbyaddr_r, [nsl], , [resolver=guess])
+    if test x$resolver = xguess && test x$specified_resolver != xguess ; then
+       dnl They wanted gethostbyaddr_r, but they can't have it, so stop.
+       AC_MSG_ERROR([no library defines gethostbyaddr_r])
+    fi
+fi
+
+dnl We still might do gethostbyaddr_r.  Figure out whether we have
+dnl glibc-style or Solaris-style gethostbyaddr_r (or neither...).
+dnl Separate determining how to call gethostbyaddr_r from testing
+dnl whether it works so we can support cross-compilation.            
+if test x$resolver = xnetdb ; then
+    AC_MSG_CHECKING([how to call gethostbyaddr_r])
+    dnl Try 7 arguments returning a struct hostent*.
+    AC_LINK_IFELSE(AC_LANG_SOURCE([`cat config/hostentp_ghba_r.c`]),
+                   [AC_MSG_RESULT([7 args])
+		    ghba_args=8
+	            AC_DEFINE(GETHOSTBYADDR_R_RETURNS_HOSTENT_P, 1,
+                    [7-argument gethostbyaddr_r returns struct hostent*])], [
+    dnl Try 8 arguments returning an int.
+    AC_LINK_IFELSE(AC_LANG_SOURCE([`cat config/int_ghba_r.c`]),
+                   [AC_MSG_RESULT([8 args, int return])
+		    ghba_args=8
+	            AC_DEFINE(GETHOSTBYADDR_R_RETURNS_INT, 1,
+                    [8-argument gethostbyaddr_r returns int])], [
+    dnl Neither.
+    AC_MSG_RESULT([don't know how])
+    resolver=guess])])
+    if test x$resolver = xguess && test x$specified_resolver != xguess ; then
+       dnl They wanted gethostbyaddr_r, but they can't have it, so stop.
+       AC_MSG_ERROR([gethostbyaddr_r has no known calling convention])
+    fi
+fi
 
-        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 the forking resolver])
-                            resolver=forking
-                        ])
-                ])
-
-            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
+dnl If we still want to do gethostbyaddr_r, and we aren't
+dnl cross-compiling, test it.
+if test x$resolver = xnetdb ; then
+    if test x$ghba_args = x8 ; then
+       testfile=int_ghba_r
+    else
+       testfile=hostentp_ghba_r
+    fi
+    AC_MSG_CHECKING(gethostbyaddr_r usability)
+    AC_RUN_IFELSE([`cat config/$testfile.c`],
+                  [AC_MSG_RESULT([yes])],
+		  [AC_MSG_RESULT([no])
+		   resolver=guess],
+		  [AC_MSG_RESULT([can't test because we are cross-compiling])])
+    if test x$resolver = xguess ; then
+        if test x$specified_resolver = xguess ; then
+           AC_MSG_RESULT([gethostbyaddr_r doesn't work, so we'll try something else])
+        else
+           dnl They wanted gethostbyaddr_r, but it doesn't work, so stop.
+           AC_MSG_ERROR([gethostbyaddr_r doesn't work])
         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.
+dnl We 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
+
+dnl They may have asked for ares.
 if test x$resolver = xares ; then
     dnl See if ares is to hand....
     AC_SEARCH_LIBS(ares_init, [ares], [
         AC_DEFINE(USE_ARES, 1, [use ARES for name resolution])
         ], [
-        dnl no ares
-        AC_MSG_RESULT([can't find ARES; dropping back to the forking resolver])
-        resolver=forking])
+        dnl They asked for ares, but we can't give it to them, so stop.
+        AC_MSG_ERROR([can't find ARES.  Re-run configure and ask for a different resolver.])])
 fi
 
+dnl Last thing to try if we haven't decided yet is netdb_1thread.
+if test x$resolver = xguess ; then
+   resolver=netdb_1thread
+fi
 
 dnl Ugh. Both the single-threaded and the forking resolvers use gethostbyaddr.
 if test x$resolver = xnetdb_1thread || test x$resolver = xforking ; then
     AC_SEARCH_LIBS(gethostbyaddr, [nsl], , [
-        AC_MSG_ERROR([not even gethostbyaddr is available
-  What sort of UNIX system is this, anyway?
-  
-  You will have to recompile with no name resolution at all.
-])
-
-        ]
-        )
+        AC_MSG_ERROR([gethostbyaddr is not available.  You will have to 
+  recompile with no name resolution at all.])])
 
     if test x$resolver = xnetdb_1thread ; then
-        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])
     else
         AC_DEFINE(USE_FORKING_RESOLVER, 1, [use a REALLY SUCKY forking resolver for name resolution])
@@ -332,7 +379,7 @@
 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])
+AC_MSG_CHECKING([POSIX threads compilation])
 thrfail=1
 oldCFLAGS=$CFLAGS
 oldLIBS=$LIBS
@@ -340,7 +387,7 @@
     CFLAGS="$oldCFLAGS $flag"
     for lib in "" -lpthread "-lpthread -lposix4" ; do
         LIBS="$oldLIBS $lib"
-        AC_TRY_RUN([`cat config/pthread.c`], [
+        AC_LINK_IFELSE(AC_LANG_SOURCE([`cat config/pthread.c`]), [
             foundthrlib=$lib
             foundthrflag=$flag
             thrfail=0
@@ -356,10 +403,16 @@
     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
 
+AC_MSG_RESULT([CFLAGS=$foundthrflag and LIBS=$foundthrlib])
+AC_MSG_CHECKING([POSIX threads usability])
+AC_RUN_IFELSE([`cat config/pthread.c`],
+	      [AC_MSG_RESULT([yes])],
+              [AC_MSG_ERROR(
+	       [it fails.  We probably guessed the wrong CFLAGS.])],
+	      [AC_MSG_RESULT([can't test because we are cross-compiling])])
+
 dnl
 dnl Are we on a system (like Solaris) that requires promiscuous mode in order to
 dnl see any outgoing packets?
@@ -374,7 +427,8 @@
 esac
 
 AC_ARG_ENABLE(default-promiscuous,
-	[--enable-default-promiscuous If enabled, iftop will operate in promiscuous mode to capture outgoing packets])
+	[  --enable-default-promiscuous If enabled, iftop will operate in promiscuous mode 
+                          to capture outgoing packets])
 
 AC_MSG_RESULT([$enable_default_promiscuous])
 
diff -ru orig/iftop-0.16/ui.c ./ui.c
--- orig/iftop-0.16/ui.c	2004-02-05 14:53:19.000000000 -0800
+++ ./ui.c	2005-06-04 11:03:06.000000000 -0700
@@ -1045,6 +1045,7 @@
                 break;
             }
             case '!': {
+#ifndef NO_SYSTEM
                 char *s;
                 dontshowdisplay = 1;
                 if ((s = edline(0, "Command", "")) && s[strspn(s, " \t")]) {
@@ -1073,6 +1074,9 @@
                     xfree(s);
                 }
                 dontshowdisplay = 0;
+#else
+                showhelp("Sorry, subshells have been disabled.");
+#endif
                 break;
             }
             case 'T':