dnl configure.in for ifstat
dnl Process this file with autoconf to create configure
dnl $Id: configure.in,v 1.51 2003/11/22 01:27:51 gael Exp $
AC_INIT(ifstat.c)

AC_ARG_ENABLE(debug,   [  --enable-debug          setup flags (gcc) for debugging (default=no)],
CFLAGS="$CFLAGS -O2 -Wall -g"
CPPFLAGS="$CPPFLAGS -DDEBUG"
LDFLAGS="$LDFLAGS",)
AC_ARG_ENABLE(optim,   [  --enable-optim          setup flags (gcc) for optimizations (default=no)],
if test "x$enable_debug" != "xyes" ; then
  CFLAGS="$CFLAGS -O3 -fomit-frame-pointer -g0"
  LDFLAGS="$LDFLAGS -s"
else
  AC_MSG_WARN([enable-optim and enable-debug are incompatible -- disabling optimizations])
fi,)

AC_CONFIG_HEADER(config.h)

dnl Programs
AC_PROG_INSTALL
AC_PROG_CC
AC_PROG_RANLIB

AC_HEADER_STDC
AC_CHECK_HEADERS(sys/time.h)
AC_HEADER_TIME
AC_CHECK_HEADERS(unistd.h ctype.h sys/types.h sys/param.h sys/mbuf.h net/route.h net/if.h net/if_var.h net/if_types.h sys/socket.h sys/ioctl.h sys/sockio.h net/soioctl.h sys/termios.h errno.h signal.h stdarg.h limits.h fcntl.h)
AC_TYPE_SIGNAL
AC_CHECK_FUNCS(sigaction snprintf)

# Options for various drivers
# auto means try if no other found, no disables, and anything else is try.
AC_ARG_WITH(proc, [  --with-proc[=FILE]      include /proc/net/dev support (default=auto)],
            [], [with_proc=auto])
AC_ARG_WITH(kstat, [  --with-kstat            include kstat(3K) support (default=auto)],
            [], [with_kstat=auto])
AC_ARG_WITH(ifmib, [  --with-ifmib            include ifmib(4) support (default=auto)],
            [], [with_ifmib=auto])
AC_ARG_WITH(ifdata, [  --with-ifdata           include ifdata ioctl support (default=auto)],
            [], [with_ifdata=auto])
AC_ARG_WITH(route, [  --with-route            include route(4) sysctl support (default=auto)],
            [], [with_route=auto])
AC_ARG_WITH(kvm,  [  --with-kvm              include kvm(3) support (default=auto)],
            [], [with_kvm=auto])
AC_ARG_WITH(dlpi,  [  --with-dlpi             include HP DLPI support (default=auto)],
            [], [with_dlpi=auto])
AC_ARG_WITH(win32,  [  --with-win32            include Win32 support (default=auto)],
            [], [with_win32=auto])
AC_ARG_WITH(snmp, [  --with-snmp[=PREFIX]    include UCD-SNMP support (default=yes)],
            [], [with_snmp=yes])
with_ioctl=no # only enabled if needed by other drivers
local=no # yes if one driver is local

# checking for proc (Linux)
if test "x$with_proc" != "xno"; then
  case "$with_proc" in
     /*) file=$with_proc ;;
     *) file=/proc/net/dev ;;
  esac
  AC_MSG_CHECKING([for proc interface in $file])
  if grep -q Inter- $file 2>/dev/null; then
    AC_DEFINE([USE_PROC], 1, [Define if you want to use /proc to get stats])
    AC_DEFINE_UNQUOTED([PROC_FILE], ["$file"], [Proc file to poll for stats])
    with_proc=yes
    with_ioctl=yes
    local=yes
  else
    with_proc=no
  fi
  AC_MSG_RESULT([$with_proc])
fi

# checking for kstat (Solaris)
test "x$with_kstat" = "xauto" -a "x$local" = "xyes" && with_kstat=no
if test "x$with_kstat" != "xno"; then
  AC_CHECK_FUNC(kstat_open, with_kstat=yes, with_kstat=no)
  if test "x$with_kstat" != "xyes" ; then
    case "x$LIBS" in
      *-lkstat*) ;;
      *) AC_CHECK_LIB(kstat, kstat_open, [LIBS="$LIBS -lkstat"; with_kstat=yes]) ;;
    esac
  fi
  if test "x$with_kstat" = "xyes" ; then
    AC_CHECK_HEADERS(kstat.h)
    AC_DEFINE([USE_KSTAT], 1, [Define if you want to use kstat to get stats])
    with_ioctl=yes
    local=yes
  fi
fi

# checking for ifmib (FreeBSD)
test "x$with_ifmib" = "xauto" -a "x$local" = "xyes" && with_ifmib=no
if test "x$with_ifmib" != "xno"; then
  AC_CHECK_HEADER(net/if_mib.h,
                  [AC_CHECK_FUNC(sysctl, with_ifmib=yes, with_ifmib=no)],
                  with_ifmib=no)
  if test "x$with_ifmib" = "xyes"; then
    AC_CHECK_HEADERS(sys/sysctl.h net/if_mib.h)
    AC_MSG_CHECKING([for working ifmib sysctl])
    # try run since interface is available on darwin but doesn't work
    AC_TRY_RUN([#include <sys/types.h>
		#include <sys/socket.h>
	        #ifdef HAVE_SYS_PARAM_H
   		#include <sys/param.h>
		#endif
		#ifdef HAVE_SYS_SYSCTL_H
		#include <sys/sysctl.h>
		#endif
		#ifdef HAVE_NET_IF_H
		#include <net/if.h>
		#endif
		#ifdef HAVE_NET_IF_MIB_H
		#include <net/if_mib.h>
		#endif
		int ifcount[] = {CTL_NET, PF_LINK, NETLINK_GENERIC,
				 IFMIB_SYSTEM, IFMIB_IFCOUNT};
		int size;
		int main() { return sysctl(ifcount, 5, NULL, &size, NULL, NULL); }],
	       [with_ifmib=yes], [with_ifmib=no], [with_ifmib=maybe])
    AC_MSG_RESULT([$with_ifmib])
    if test "x$with_ifmib" != "xno" ; then
      AC_DEFINE([USE_IFMIB], 1, [Define if you want to use if_mib to get stats])
      local=yes
    fi
  fi
fi

# checking for ioctl ifdata (Irix, ...)
test "x$with_ifdata" = "xauto" -a "x$local" = "xyes" && with_ifdata=no
if test "x$with_ifdata" != "xno"; then
  AC_MSG_CHECKING([for SIOCGIFDATA and ifdatareq])
  AC_TRY_COMPILE([#include <sys/types.h>
		  #include <sys/socket.h>
		  #include <sys/ioctl.h>
		  #ifdef HAVE_SYS_SOCKIO_H
                  #include <sys/sockio.h>
		  #endif
		  #ifdef HAVE_NET_SOIOCTL_H
 		  #include <net/soioctl.h>
		  #endif
		  #include <net/if.h>],
		 [struct ifdatareq ifd;
		  ioctl(0, SIOCGIFDATA, (char *) &ifd);
		  ifd.ifd_ifd.ifi_ibytes = ifd.ifd_ifd.ifi_obytes;],
		 with_ifdata=yes, with_ifdata=no)
  AC_MSG_RESULT([$with_ifdata])
  test "x$with_ifdata" = "xno" && with_ifdata=checkifr
fi
if test "x$with_ifdata" = "xcheckifr"; then
  AC_MSG_CHECKING([for SIOCGIFDATA and ifreq.ifr_data])
  AC_TRY_COMPILE([#include <sys/types.h>
		  #include <sys/socket.h>
		  #include <sys/ioctl.h>
		  #ifdef HAVE_SYS_SOCKIO_H
                  #include <sys/sockio.h>
		  #endif
		  #ifdef HAVE_NET_SOIOCTL_H
 		  #include <net/soioctl.h>
		  #endif
		  #include <net/if.h>],
    	         [struct ifreq ifr; struct if_data ifd;
                  ifr.ifr_data = &ifd;
		  ioctl(0, SIOCGIFDATA, (char *) &ifr);
		  ifd.ifi_ibytes = ifd.ifi_obytes;],
		  [with_ifdata=yes
                   AC_DEFINE([HAVE_IFREQ_IFR_DATA], 1,
                             [Define if you have a ifr_data member in struct ifreq])],
	           with_ifdata=no)
  AC_MSG_RESULT([$with_ifdata])
fi
if test "x$with_ifdata" = "xyes"; then
  AC_DEFINE([USE_IFDATA], 1, [Define if you want to use ifdata to get stats])
  local=yes
  with_ioctl=yes
fi

# checking for route sysctl (*BSDs)
test "x$with_route" = "xauto" -a "x$local" = "xyes" && with_route=no
if test "x$with_route" != "xno"; then
  AC_CHECK_HEADERS(sys/sysctl.h net/if_dl.h)
  AC_CHECK_FUNC(sysctl, with_route=yes, with_route=no)
  if test "x$with_route" = "xyes"; then
    AC_MSG_CHECKING([for route info sysctl])
    AC_TRY_COMPILE([#include <sys/types.h>
	  	    #include <sys/socket.h>
 		    #ifdef HAVE_SYS_PARAM_H
   		    #include <sys/param.h>
		    #endif
 		    #ifdef HAVE_SYS_SYSCTL_H
   		    #include <sys/sysctl.h>
		    #endif
                    #ifdef HAVE_NET_IF_H
                    #include <net/if.h>
                    #endif
		    #ifdef HAVE_NET_IF_DL_H
	   	    #include <net/if_dl.h>
		    #endif],
		   [struct sockaddr_dl dl;
                    struct if_msghdr ifm;
		    int iflist[] = {CTL_NET, PF_ROUTE, 0, AF_LINK, NET_RT_IFLIST};
                    ifm.ifm_type = dl.sdl_nlen;
                    dl.sdl_data + ifm.ifm_msglen;
		    ifm.ifm_data.ifi_ibytes;],
		   with_route=yes, with_route=no)
    AC_MSG_RESULT([$with_route])
    if test "x$with_route" != "xno"; then
      AC_DEFINE([USE_ROUTE], 1, [Define this if you want to use roue(4) sysctl to get stats])
      local=yes
    fi
  fi
fi

# checking for kvm (*BSDs)
test "x$with_kvm" = "xauto" -a "x$local" = "xyes" && with_kvm=no
if test "x$with_kvm" != "xno"; then
  AC_CHECK_FUNC(kvm_openfiles, with_kvm=yes, with_kvm=no)
  if test "x$with_kvm" != "xyes" ; then
    case "x$LIBS" in
     *-lkvm*) ;;
     *) AC_CHECK_LIB(kvm, kvm_openfiles, [LIBS="$LIBS -lkvm"; with_kvm=yes]) ;;
    esac
  fi
  if test "x$with_kvm" != "xyes"; then
    # see if emulation is possible
    AC_CHECK_HEADERS(nlist.h, [
      AC_CHECK_FUNCS(knlist, [
        with_kvm=yes
        AC_MSG_CHECKING([whether knlist takes 3 arguments])
        AC_TRY_COMPILE([#include <nlist.h>],[knlist((struct nlist *) 0, 0, 10);],
                       knlist3=yes, knlist3=no)
        AC_MSG_RESULT([$knlist3])
        if test "x$knlist3" = "xyes"; then
	  AC_DEFINE([HAVE_KNLIST_ARGS3], 1,
		    [Define if knlist needs 3 arguments])
        fi
      ], [AC_CHECK_FUNC(nlist, [with_kvm=yes])])
    ])
    if test "x$with_kvm" = "xyes"; then
      AC_CHECK_FUNCS(readx)
      AC_CHECK_HEADERS(paths.h)
    fi
  else
    AC_CHECK_HEADERS(kvm.h)
    AC_DEFINE([HAVE_KVM], 1, [Define if you have the kvm(3) interface])
  fi
  if test "x$with_kvm" = "xyes"; then
    AC_MSG_CHECKING([whether struct ifnet has needed interface data])
    AC_TRY_COMPILE([#include <sys/types.h>
                    #include <sys/socket.h>
		    #include <net/if.h>
		    #ifdef HAVE_NET_IF_VAR_H
		    #include <net/if_var.h>
		    #endif],[struct ifnet in; in.if_ibytes = in.if_obytes;
                             in.if_type = in.if_flags],
                   with_kvm=yes, with_kvm=no)
    AC_MSG_RESULT([$with_kvm])
  fi
  if test "x$with_kvm" = "xyes"; then
    AC_MSG_CHECKING([for struct ifnet if_xname member])
    AC_TRY_COMPILE([#include <sys/types.h>
                    #include <sys/socket.h>
		    #include <net/if.h>
		    #ifdef HAVE_NET_IF_VAR_H
		    #include <net/if_var.h>
		    #endif],[struct ifnet in; in.if_xname[0] = 'a';],
                   ifxname=yes, ifxname=no)
    test "x$ifxname" = "xyes" && AC_DEFINE([HAVE_IFNET_IF_XNAME], 1,
	[Define if you have a if_xname member in struct ifnet])
    AC_MSG_RESULT([$ifxname])

    AC_MSG_CHECKING([for struct ifnet if_next member])
    AC_TRY_COMPILE([#include <sys/types.h>
                    #include <sys/socket.h>
		    #include <net/if.h>
		    #ifdef HAVE_NET_IF_VAR_H
		    #include <net/if_var.h>
		    #endif],[struct ifnet in; in.if_next;],
                   ifnext=yes, ifnext=no)
    AC_MSG_RESULT([$ifnext])
    if test "x$ifnext" = "xyes"; then
        AC_DEFINE([HAVE_IFNET_IF_NEXT], 1,
                  [Define if you have a if_next member in struct ifnet])
    else 
      AC_MSG_CHECKING([for struct ifnet if_link member])
      AC_TRY_COMPILE([#include <sys/types.h>
                      #include <sys/socket.h>
	 	      #include <net/if.h>
  		      #ifdef HAVE_NET_IF_VAR_H
		      #include <net/if_var.h>
		      #endif],[struct ifnet in; in.if_link;],
                     iflink=yes, iflink=no)
      test "x$iflink" = "xyes" && AC_DEFINE([HAVE_IFNET_IF_LINK], 1,
	  [Define if you have a if_link member in struct ifnet])
      AC_MSG_RESULT([$iflink])
    fi

    AC_DEFINE([USE_KVM], 1, [Define if you want to use kvm to get stats])
    AC_MSG_WARN([you might need to make ifstat SGID kmem to run as simple user])
    local=yes
  fi
fi

# checking for hp dlpi interface
test "x$with_dlpi" = "xauto" -a "x$local" = "xyes" && with_dlpi=no
if test "x$with_dlpi" != "xno"; then
  AC_CHECK_HEADERS(sys/dlpi.h sys/dlpi_ext.h stropts.h sys/mib.h)
  AC_MSG_CHECKING([for dlpi streams interface])
  AC_TRY_COMPILE([#ifdef HAVE_UNISTD_H
		  #include <unistd.h>
                  #endif
                  #ifdef HAVE_SYS_DLPI_H
                  #include <sys/dlpi.h>
                  #endif
                  #ifdef HAVE_SYS_DLPI_EXT_H
                  #include <sys/dlpi_ext.h>
                  #endif
                  #ifdef HAVE_STROPTS_H
                  #include <sys/stropts.h>
                  #endif
                  #ifdef HAVE_SYS_MIB_H
                  #include <sys/mib.h>
                  #endif], [mib_ifEntry mib; dl_hp_ppa_req_t req;
                  struct strbuf ctlptr; putmsg(0, &ctlptr, NULL, 0);],
		with_dlpi=yes, with_dlpi=no)
  AC_MSG_RESULT([$with_dlpi])
  if test "x$with_dlpi" = "xyes"; then
    AC_DEFINE([USE_DLPI], 1, [Define if you want to use dlpi to get stats])
    local=yes
  fi
fi

test "x$with_win32" = "xauto" -a "x$local" = "xyes" && with_win32=no
if test "x$with_win32" != "xno"; then
  AC_MSG_CHECKING([for win32 GetIfTable interface])
  OLIBS="$LIBS"
  LIBS="$LIBS -liphlpapi"
  AC_TRY_LINK([#include <windows.h>
               #include <iphlpapi.h>], [GetIfTable(NULL, NULL, 0);],
	       [with_win32=yes], [with_win32=no; LIBS="$OLIBS"])
  AC_MSG_RESULT([$with_win32])
  if test "x$with_win32" = "xyes"; then
    AC_DEFINE([USE_WIN32], 1, [Define if you want to use win32 to get stats])
    local=yes
  fi
fi  

# checking for ioctl (siocgifconf) to get interfaces
test "x$with_ioctl" = "xauto" -a "x$local" = "xyes" && with_ioctl=no
if test "x$with_ioctl" != "xno"; then
  AC_DEFINE([USE_IOCTL], 1, [Define if you want to use ioctls to get if list])
  AC_CHECK_FUNC(socket, checksocket=no, checksocket=yes)
  if test "x$checksocket" = "xyes"; then 
    case "x$LIBS" in
      *-lsocket*);;
      *) AC_CHECK_LIB(socket, socket) ;;
    esac
  fi
  AC_CHECK_FUNC(if_nameindex, ifnameindex=yes, ifnameindex=no)
  if test "x$ifnameindex" != "xyes"; then 
    case "x$LIBS" in
      *-lnsl*);;
      *) AC_CHECK_LIB(nsl, if_nameindex, [ifnameindex=yes; LIBS="$LIBS -lnsl"]) ;;
    esac
  fi
  if test "x$ifnameindex" != "xyes"; then
    AC_MSG_CHECKING([for sockaddr sa_len member])
    AC_TRY_COMPILE([
    #include <sys/types.h>
    #include <sys/socket.h>],[struct sockaddr sa; sa.sa_len = 1;],
                   salen=yes, salen=no)
    test "x$salen" = "xyes" && AC_DEFINE([HAVE_SOCKADDR_SA_LEN], 1,
	[Define if you have a sa_len member in struct sockaddr])
    AC_MSG_RESULT([$salen])
  else
    AC_DEFINE([USE_IFNAMEINDEX], 1,
	[Define if you want ot use if_nameindex to find interfaces])
  fi
fi

# checking for snmp (NET-SNMP/UCD-SNMP)
if test "x$with_snmp" != "xno" ; then
  OCPPFLAGS="$CPPFLAGS"
  OLDFLAGS="$LDFLAGS"
  snmp_ok=no

  AC_PATH_PROG(netsnmpconfig, [net-snmp-config], [no], $PATH:$with_snmp)
  if test "x$netsnmpconfig" != "xno"; then
    CPPFLAGS="$CPPFLAGS `$netsnmpconfig --base-cflags 2>/dev/null`"
    LDFLAGS="$LDFLAGS `$netsnmpconfig --libs 2>/dev/null`"
    AC_MSG_CHECKING([whether net-snmp-config hints compiles and links fine])
    AC_TRY_LINK([#include<net-snmp/net-snmp-config.h>], [snmp_sess_init((void *) 0);],
                [snmp_ok=yes], [snmp_ok=no])
    AC_MSG_RESULT([$snmp_ok])
    if test "x$snmp_ok" = "xyes"; then
      with_snmp=yes
      snmp_type=net
    else
      CPPFLAGS="$OCPPFLAGS"
      LDFLAGS="$OLDFLAGS"
    fi
  fi

  if test "x$snmp_ok" != "xyes"; then
    if test "x$with_snmp" != "xyes" ; then
      CPPFLAGS="$CPPFLAGS -I$with_snmp/include"
      LDFLAGS="$LDFLAGS -L$with_snmp/lib"
    fi
    AC_CHECK_HEADER(net-snmp/net-snmp-config.h, snmp_type=net,
	  	    [AC_CHECK_HEADER(ucd-snmp/ucd-snmp-config.h,
                                     snmp_type=ucd, with_snmp=no)])

    if test "x$with_snmp" != "xno"; then
      if test "x$snmp_type" = "xnet"; then
         libsnmp="-lnetsnmp"
      else
         libsnmp="-lsnmp"
      fi

      with_snmp=no
      SNMPLIBALONE="$libsnmp"
      # Setting to be able to force linking with -lcrypto....
      # This is needed on OpenBSD (at least) where the snmplib port links without -lcrypto,
      # but fails to run.
      AC_ARG_WITH(libcrypto,
                  [  --with-libcrypto        force link with -lcrypto for UCD-SNMP (default=no)],
	          [], [with_libcrypto=no])
      if test "x$with_libcrypto" = "xyes" ; then
        SNMPLIBALONE=""
      fi
      for lib in $SNMPLIBALONE "$libsnmp -lcrypto" ; do
        if test "x$with_snmp" != "xyes" ; then
          AC_MSG_CHECKING([for snmp support in $lib])
          OLIBS="$LIBS"
          LIBS="$LIBS $lib"
          AC_TRY_LINK([], [snmp_sess_init();],
                      [with_snmp=yes], [LIBS="$OLIBS"])
          AC_MSG_RESULT([$with_snmp])
        fi
      done
    fi
  fi
  if test "x$with_snmp" = "xyes" ; then
    AC_DEFINE([USE_SNMP], 1, [Define if you have SNMP support])
    if test "x$snmp_type" = "xnet"; then
       AC_DEFINE([HAVE_NET_SNMP], 1,
	         [Define if your SNMP implementation is net-snmp v5.0 or greater])
    fi
    SNMPSRC=snmp.c
    AC_SUBST(SNMPSRC)
    # hint users about the possible needed option
    case `uname -s` in
     *OpenBSD*)
       case "$LIBS" in
        *-lcrypto*) ;;
	*) AC_MSG_WARN([SNMP test linked fine, but you might need to use --with-libcrypto for SNMP to work on this OS.]);;
       esac ;;
    esac
  else
    CPPFLAGS="$OCPPFLAGS"
    LDFLAGS="$OLDFLAGS"
  fi
fi

# checking that we do have at least one driver
if test "x$local" != "xyes"; then
  if test "x$with_snmp" = "xyes"; then
    AC_MSG_WARN([no native stats gathering mechanism found; will use SNMP.])
  else
    AC_MSG_ERROR([no statistics gathering methods found, porting needed.])
  fi
fi

# check for library
AC_ARG_ENABLE(library,   [  --enable-library        enable build and installation of libifstat (default=no)], LIBTARGET=libifstat.a, )

dnl Version
VERSION="`cat VERSION`"
test -z $VERSION && VERSION="0.0"
# perl -MPOSIX -e 'print strftime("%Y%m%d", localtime((stat("CVS"))[9]));'
test -d CVS && VERSION="$VERSION-cvs"`date +%Y%m%d`
AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version])

dnl Output
AC_SUBST(VERSION)
AC_SUBST(CFLAGS)
AC_SUBST(CPPFLAGS)
AC_SUBST(LDFLAGS)
AC_SUBST(LIBTARGET)

AC_OUTPUT(Makefile)
