AC_INIT(file.c)
AC_CONFIG_HEADER(file_machine.h)

sinclude(../module_configure.in)

AC_HAVE_HEADERS(sys/types.h arpa/inet.h sys/socketvar.h netinet/in.h \
 sys/mount.h ustat.h sys/statfs.h sys/statvfs.h sys/vfs.h sys/param.h \
 sys/socket.h sys/stream.h sys/protosw.h netdb.h sys/sysproto.h)
AC_HEADER_DIRENT
AC_CHECK_LIB(bind, __inet_ntoa)
AC_CHECK_LIB(socket, socket)

AC_HAVE_FUNCS(getwd perror fork1 readdir_r statvfs statfs ustat)

if test x$ac_cv_func_readdir_r = xyes ; then
  AC_MSG_CHECKING(if readdir_r takes 2(Solaris & HPUX) or 3(Posix) arguments)
  AC_CACHE_VAL(pike_cv_func_posix_readdir_r, [
    AC_TRY_RUN([
/* For _REENTRANT */
#include "machine.h"
#ifndef POSIX_SOURCE
#define POSIX_SOURCE
#endif
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#else
#ifdef HAVE_SYS_NDIR_H
#include <sys/ndir.h>
#endif
#ifdef HAVE_SYS_DIR_H
#include <sys/dir.h>
#endif
#ifdef HAVE_NDIR_H
#include <ndri.h>
#endif
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_SYS_SYSPROTO_H
#include <sys/sysproto.h>
#endif

int main()
{
  exit(0);

  /* NOT REACHED */
  readdir_r((DIR *)0, (struct dirent *)0);
}
],pike_cv_func_posix_readdir_r=no,pike_cv_func_posix_readdir_r=yes)
  ])

if test x$pike_cv_func_posix_readdir_r = xyes ; then
  AC_MSG_RESULT(3 - POSIX)
  AC_DEFINE(HAVE_POSIX_READDIR_R)
else
  AC_MSG_RESULT(2)

  AC_MSG_CHECKING(if readdir_r returns an int(HPUX) or a pointer(Solaris))
  AC_CACHE_VAL(pike_cv_func_solaris_style_readdir_r, [
    AC_TRY_RUN([
/* For _REENTRANT */
#include "machine.h"
#ifndef POSIX_SOURCE
#define POSIX_SOURCE
#endif
#include <sys/errno.h>
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#else
#ifdef HAVE_SYS_NDIR_H
#include <sys/ndir.h>
#endif
#ifdef HAVE_SYS_DIR_H
#include <sys/dir.h>
#endif
#ifdef HAVE_NDIR_H
#include <ndri.h>
#endif
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_SYS_SYSPROTO_H
#include <sys/sysproto.h>
#endif

extern int errno;

int main()
{
  DIR *dir = opendir(".");
  char tmp[1024];
  unsigned long retval;

  retval = (unsigned long) readdir_r(dir, (struct dirent *)tmp);

  if (retval == (unsigned long)tmp) {
    /* Solaris */
    exit(0);
  } else if (retval == ~0UL) {
    /* HPUX */
    exit(1);
  } else if (!retval) {
    if (!errno) {
      /* HPUX */
      exit(1);
    } else {
      /* Solaris */
      exit(0);
    }
  } else {
    /* Unknown, but probably Solaris */
    exit(0);
  }
}
],pike_cv_func_solaris_style_readdir_r=yes,pike_cv_func_solaris_style_readdir_r=no)
  ])
  if test x$pike_cv_func_solaris_style_readdir_r = xyes ; then
    AC_MSG_RESULT(Solaris style)
    AC_DEFINE(HAVE_SOLARIS_READDIR_R)
  else
    AC_MSG_RESULT(HPUX style)
    AC_DEFINE(HAVE_HPUX_READDIR_R)
  fi
fi

else :; fi

if test x$ac_cv_func_statfs = xyes ; then
  AC_MSG_CHECKING(if statfs takes 2(BSD) or 4(SysV) arguments)
  AC_CACHE_VAL(pike_cv_func_sysv_statfs, [
    AC_TRY_RUN([
#ifndef POSIX_SOURCE
#define POSIX_SOURCE
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_SYS_SYSPROTO_H
#include <sys/sysproto.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <sys/stat.h>
#ifdef HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
#ifdef HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif

int main()
{
  exit(0);

  /* NOT REACHED */
  statfs((char *)0, (struct statfs *)0, 0, 0);
}
],pike_cv_func_sysv_statfs=yes,pike_cv_func_sysv_statfs=no)
  ])
  if test x$pike_cv_func_sysv_statfs = xyes ; then
    AC_MSG_RESULT(SysV style)
    AC_DEFINE(HAVE_SYSV_STATFS)
  else
    AC_MSG_RESULT(BSD style)
  fi

  AC_MSG_CHECKING(if the struct statfs exists)
  AC_CACHE_VAL(pike_cv_struct_statfs, [
    AC_TRY_COMPILE([
#ifndef POSIX_SOURCE
#define POSIX_SOURCE
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_SYS_SYSPROTO_H
#include <sys/sysproto.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <sys/stat.h>
#ifdef HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
#ifdef HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
#ifdef HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
    ], [
      struct statfs st;
    ], [ pike_cv_struct_statfs=yes
    ], [ pike_cv_struct_statfs=no
    ])
  ])
  AC_MSG_RESULT($pike_cv_struct_statfs)
  if test x$pike_cv_struct_statfs = xyes; then
    AC_DEFINE(HAVE_STRUCT_STATFS)

    AC_MSG_CHECKING(if the struct statfs has the member f_bavail)
    AC_CACHE_VAL(pike_cv_struct_statfs_f_bavail, [
      AC_TRY_COMPILE([
#ifndef POSIX_SOURCE
#define POSIX_SOURCE
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_SYS_SYSPROTO_H
#include <sys/sysproto.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <sys/stat.h>
#ifdef HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
#ifdef HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
#ifdef HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
      ], [
        struct statfs st;
        st.f_bavail = 0;
      ], [ pike_cv_struct_statfs_f_bavail=yes
      ], [ pike_cv_struct_statfs_f_bavail=no
      ])
    ])
    AC_MSG_RESULT($pike_cv_struct_statfs_f_bavail)
    if test x$pike_cv_struct_statfs_f_bavail = xyes; then
      AC_DEFINE(HAVE_STATFS_F_BAVAIL)
    else :; fi
  else
    # No struct statfs. We might be running ULTRIX,
    # so check for struct fs_data.
    AC_MSG_CHECKING(if the struct fs_data exists)
    AC_CACHE_VAL(pike_cv_struct_fs_data, [
      AC_TRY_COMPILE([
#ifndef POSIX_SOURCE
#define POSIX_SOURCE
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_SYS_SYSPROTO_H
#include <sys/sysproto.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <sys/stat.h>
#ifdef HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
#ifdef HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
#ifdef HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
      ], [
        struct fs_data st;
      ], [ pike_cv_struct_fs_data=yes
      ], [ pike_cv_struct_fs_data=no
      ])
    ])
    AC_MSG_RESULT($pike_cv_struct_fs_data)
    if test x$pike_cv_struct_fs_data = xyes; then
      AC_DEFINE(HAVE_STRUCT_FS_DATA)
    else :; fi
  fi
else :; fi

AC_MSG_CHECKING(for working (and failsafe) strerror)
AC_CACHE_VAL(pike_cv_func_failsafe_strerror,
[
AC_TRY_RUN([
#include <stdio.h>
#include <string.h>
int main()
{
  int e;
  char *s;
  for(e=0;e<256;e++) if(strerror(e)) if(strerror(e)[0]=='\b') exit(1);
  exit(0);
}
],pike_cv_func_failsafe_strerror=yes,pike_cv_func_failsafe_strerror=no)
])

if test "$pike_cv_func_failsafe_strerror" = yes; then
  AC_MSG_RESULT(yes)
  AC_DEFINE(HAVE_STRERROR)
else
  AC_MSG_RESULT(no)
fi

AC_MSG_CHECKING(for select on AF_UNIX sockets)
AC_CACHE_VAL(pike_cv_select_on_unix_sockets,
[
AC_TRY_RUN([
#ifndef POSIX_SOURCE
#define POSIX_SOURCE
#endif
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif

int main()
{
  fd_set tmp;
  struct timeval foo;
  int fds[2];
  char x;

  if(socketpair(AF_UNIX, SOCK_STREAM, 0, fds)<0)
  {
    fprintf(stderr,"socketpair() failed\n");
    exit(1);
  }

  if(shutdown(fds[1],1))
  {
    fprintf(stderr,"shutdown failed\n");
    exit(9);
  }
 
  if(shutdown(fds[0],1))
  {
    fprintf(stderr,"shutdown failed\n");
    exit(9);
  }
  close(fds[0]);

  foo.tv_sec=5;
  foo.tv_usec=0;

  FD_ZERO(&tmp);
  FD_SET(fds[1], &tmp);
  if(select(fds[1]+1,&tmp, 0,0,&foo)<=0)
  {
    fprintf(stderr,"select() does report closed sockets properly\n");
    exit(2);
  }

  if(!FD_ISSET(fds[1], &tmp))
  {
    fprintf(stderr,"FD_ISSET does not report closed sockets properly\n");
    exit(3);
  }

  if(socketpair(AF_UNIX, SOCK_STREAM, 0, fds)<0)
    exit(1);

  foo.tv_sec=1;
  foo.tv_usec=0;
  FD_ZERO(&tmp);
  FD_SET(fds[1], &tmp);

  if(select(fds[1]+1,&tmp, 0,0,&foo)>0)
  {
    fprintf(stderr,"select() always falls through\n");
    exit(4);
  }

  if(write(fds[0],"x",1)!=1)
  {
    fprintf(stderr,"write() failed\n");
    exit(1);
  }
  
  foo.tv_sec=1;
  foo.tv_usec=0;
  FD_ZERO(&tmp);
  FD_SET(fds[1], &tmp);

  if(select(fds[1]+1,&tmp, 0,0,&foo)<=0)
  {
    fprintf(stderr,"select() never falls through\n");
    exit(5);
  }
 
  if(!FD_ISSET(fds[1], &tmp))
  {
    fprintf(stderr,"select() does not modify read set properly\n");
    exit(6);
  }

  if(read(fds[1], &x, 1)!=1)
  {
    fprintf(stderr,"read() failed\n");
    exit(1);
  }

  if(shutdown(fds[0],1))
  {
    fprintf(stderr,"socketpair() failed\n");
    exit(1);
  }

  foo.tv_sec=1;
  foo.tv_usec=0;
  FD_ZERO(&tmp);
  FD_SET(fds[1], &tmp);

  if(select(fds[1]+1,&tmp, 0,0,&foo)<=0)
  {
    fprintf(stderr,"select() does not report shutdown()\n");
    exit(7);
  }
 
  if(!FD_ISSET(fds[1], &tmp))
  {
    fprintf(stderr,"select() does not modify read set properly on shutdown()\n");
    exit(8);
  }

  exit(0);
}


],pike_cv_select_on_unix_sockets=yes,pike_cv_select_on_unix_sockets=no)
])

AC_MSG_RESULT($pike_cv_select_on_unix_sockets)
if test x$pike_cv_select_on_unix_sockets = xyes ; then
  AC_DEFINE(HAVE_SOCKETPAIR)
fi


AC_MSG_CHECKING(size of socket buffers)
AC_CACHE_VAL(pike_cv_socket_buffer_max,
[
AC_TRY_RUN([
#ifndef POSIX_SOURCE
#define POSIX_SOURCE
#endif
#include <stdio.h>
#include <sys/types.h>
#include <sys/param.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/socket.h>

int main()
{
  FILE *f;
  int fd, try, tmp;

  fd=socket(AF_INET, SOCK_STREAM, 0);

  if(fd < 0) return 1;

  try=1024;
  while(try < 65000)
  {
    tmp=try*2;
    if(setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&tmp, sizeof(int)) < 0)
    {
      break;
    }
    try*=2;
  }
  f=fopen("conftest.out.2","w");
  fprintf(f,"%d\n",try);
  fclose(f);
  
  return 0;
}],
pike_cv_socket_buffer_max=`cat conftest.out.2`
,
pike_cv_socket_buffer_max=0
)])

AC_DEFINE_UNQUOTED(SOCKET_BUFFER_MAX,$pike_cv_socket_buffer_max)
AC_MSG_RESULT($pike_cv_socket_buffer_max)


AC_MSG_CHECKING(for working getcwd)
AC_CACHE_VAL(pike_cv_func_working_getcwd,
[
AC_TRY_RUN([
#ifndef POSIX_SOURCE
#define POSIX_SOURCE
#endif
#include <unistd.h>
#include <signal.h>

int sig_child(int arg)
{
#ifdef HAVE_WAITPID
  waitpid(-1,0,WNOHANG);
#else
#ifdef HAVE_WAIT3
  wait3(0,WNOHANG,0);
#else
#ifdef HAVE_WAIT4
  wait3(-1,0,WNOHANG,0);
#else

  /* Leave'em hanging */

#endif /* HAVE_WAIT4 */
#endif /* HAVE_WAIT3 */
#endif /* HAVE_WAITPID */

#ifdef SIGNAL_ONESHOT
  my_signal(SIGCHLD, sig_child);
#endif
}

int sig_alarm() { exit(1); }

int main()
{
  char *tmp;
  signal(SIGCHLD,sig_child);
  signal(SIGALRM,sig_alarm);
  alarm(4);
  tmp=getcwd(0,10000);
  if(tmp && strlen(tmp) <10000) exit(0);
  exit(1);
}
],pike_cv_func_working_getcwd=yes,pike_cv_func_working_getcwd=no)])

if test "$pike_cv_func_working_getcwd" = yes; then
  AC_MSG_RESULT(yes)
  AC_DEFINE(HAVE_WORKING_GETCWD)
else
  AC_MSG_RESULT(no)
fi

AC_OUTPUT(Makefile,echo FOO >stamp-h )


