Prepare libusual for pgbouncer: autoconf/win32
authorMarko Kreen <markokr@gmail.com>
Sat, 18 Apr 2009 22:02:51 +0000 (01:02 +0300)
committerMarko Kreen <markokr@gmail.com>
Mon, 20 Apr 2009 06:54:44 +0000 (09:54 +0300)
- Generate usual/config.h via autoconf.
- m4/usual.m4 for common autoconf macros
- include base.h in all headers
- base.h includes config.h
- Import win32 compat from pgbouncer: usual/compat.[ch] + usual/win32.h
- time.[ch] uses usec_t instead of timeval now
- md5 detects endianess via AC_BIGENDIAN
- Include <usual/compat.h> where needed.

26 files changed:
Makefile
config.mak.in [new file with mode: 0644]
configure.ac [new file with mode: 0644]
m4/usual.m4 [new file with mode: 0644]
usual/aatree.c
usual/aatree.h
usual/base.h
usual/compat.c [new file with mode: 0644]
usual/compat.h [new file with mode: 0644]
usual/daemon.c
usual/daemon.h
usual/event.c
usual/event.h
usual/fileutil.c
usual/logging.c
usual/lookup3.h
usual/md5.c
usual/md5.h
usual/safeio.c
usual/safeio.h
usual/socket.c
usual/socket.h
usual/string.h
usual/time.c
usual/time.h
usual/win32.h [new file with mode: 0644]

index b6e8d763de04e2fa2c4fa76958fe3f2833bb87c8..2a56130624bac9e49e6e1ba431a732c6631c684b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,9 @@
+
+-include config.mak
+
 # config
-DEFS = -DCASSERT
-CC = gcc
-MKAR = ar rcs
-CFLAGS = -O2 -g -Wall $(WFLAGS)
+MKAR = $(AR) rcs
+CFLAGS += $(WFLAGS)
 CPPFLAGS = $(USUAL_CPPFLAGS)
 
 # sources
@@ -40,15 +41,34 @@ libusual.a: $(objs)
        $(E) "  AR" $@
        $(Q) $(MKAR) $@ $(objs)
 
-obj/%.o: usual/%.c $(hdrs)
+obj/%.o: usual/%.c config.mak $(hdrs)
        @mkdir -p obj
        $(E) "  CC" $<
        $(Q) $(CC) -c -o $@ $(DEFS) $(CPPFLAGS) $(CFLAGS) $<
 
-obj/testcompile: test/compile.c libusual.a $(hdrs)
+obj/testcompile: test/compile.c libusual.a config.mak $(hdrs)
        $(E) "  CHECK" $<
-       $(Q) $(CC) -o $@ $(DEFS) $(CPPFLAGS) $(CFLAGS) $< $(USUAL_LDFLAGS) $(USUAL_LIBS)
+       $(Q) $(CC) -o $@ $(DEFS) $(CPPFLAGS) $(CFLAGS) $< $(USUAL_LDFLAGS) $(USUAL_LIBS) $(LIBS)
 
 clean:
-       rm -f libusual.a obj/*.o obj/test*
+       rm -f libusual.a obj/*.o obj/test* aclocal* config.log
+       rm -rf autom4te*
+
+distclean: clean
+       rm -f config.mak usual/config.h
+
+boot:
+       rm -rf usual/config.*
+       aclocal -I ./m4
+       autoheader
+       autoconf
+       rm -rf aclocal* autom4te.*
+
+config.mak: usual/config.h
+       @echo "Config out-of-date, please run ./configure again"
+       @exit 1
+
+usual/config.h:
+       @echo "Please run ./configure first"
+       @exit 1
 
diff --git a/config.mak.in b/config.mak.in
new file mode 100644 (file)
index 0000000..3d8a85b
--- /dev/null
@@ -0,0 +1,41 @@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+
+PORTNAME = @PORTNAME@
+
+DEFS = @DEFS@
+LIBS = @LIBS@
+CC = @CC@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CFLAGS = @CFLAGS@
+LDFLAGS = @LDFLAGS@
+
+AR = @AR@
+STRIP = @STRIP@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+datarootdir = @datarootdir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+docdir = @docdir@
+mandir = @mandir@
+
+top_builddir = @top_builddir@
+srcdir = @srcdir@
+abs_srcdir = @abs_srcdir@
+top_srcdir = @top_srcdir@
+abs_top_srcdir = @abs_top_srcdir@
+builddir = @builddir@
+abs_builddir = @abs_builddir@
+abs_top_builddir = @abs_top_builddir@
+
+# autoconf does not want to find 'install'
+# if im not using automake...
+INSTALL = @INSTALL@
+BININSTALL = @BININSTALL@
+
+enable_debug = @enable_debug@
+
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..cdb109c
--- /dev/null
@@ -0,0 +1,26 @@
+dnl Process this file with autoconf to produce a configure script.
+
+AC_INIT(libusual, 0.1)
+AC_CONFIG_SRCDIR(usual/base.h)
+AC_CONFIG_HEADER(usual/config.h)
+AC_PREREQ([2.59])
+
+AC_USUAL_PORT_CHECK
+
+AC_USUAL_PROGRAM_CHECK
+
+AC_USUAL_HEADER_CHECK
+
+AC_USUAL_TYPE_CHECK
+
+AC_USUAL_FUNCTION_CHECK
+
+AC_USUAL_CASSERT
+
+AC_USUAL_WERROR
+
+AC_USUAL_DEBUG
+
+dnl Output findings
+AC_OUTPUT([config.mak])
+
diff --git a/m4/usual.m4 b/m4/usual.m4
new file mode 100644 (file)
index 0000000..159794c
--- /dev/null
@@ -0,0 +1,180 @@
+
+dnl Those depend on correct order:
+dnl  AC_USUAL_PROGRAM_CHECK
+dnl  AC_USUAL_HEADER_CHECK
+dnl  AC_USUAL_TYPE_CHECK
+dnl  AC_USUAL_FUNCTION_CHECK
+dnl Order does not matter:
+dnl  AC_USUAL_CASSERT
+dnl  AC_USUAL_WERROR
+dnl  AC_USUAL_DEBUG
+
+dnl
+dnl  AC_USUAL_PORT_CHECK:  PORTNAME=win32/unix
+dnl
+AC_DEFUN([AC_USUAL_PORT_CHECK], [
+AC_MSG_CHECKING([target host type])
+xhost="$host_alias"
+if test "x$xhost" = "x"; then
+  xhost=`uname -s`
+fi
+case "$xhost" in
+*cygwin* | *mingw* | *pw32* | *MINGW*)
+   LIBS="$LIBS -lws2_32"
+   PORTNAME=win32;;
+*) PORTNAME=unix ;;
+esac
+AC_SUBST(PORTNAME)
+AC_MSG_RESULT([$PORTNAME])
+])
+
+
+dnl
+dnl AC_USUAL_PROGRAM_CHECK:  Simple C environment: CC, CPP, INSTALL
+dnl
+AC_DEFUN([AC_USUAL_PROGRAM_CHECK], [
+AC_PROG_CC
+AC_PROG_CPP
+dnl Check if compiler supports __func__
+AC_CACHE_CHECK([whether compiler supports __func__], pgac_cv_funcname_func,
+  [AC_TRY_COMPILE([#include <stdio.h>], [printf("%s\n", __func__);],
+    [pgac_cv_funcname_func=yes], [pgac_cv_funcname_func=no])])
+if test x"$pgac_cv_funcname_func" = xyes ; then
+  AC_DEFINE(HAVE_FUNCNAME__FUNC, 1,
+    [Define to 1 if your compiler understands __func__.])
+fi
+dnl Check if linker supports -Wl,--as-needed
+if test "$GCC" = "yes"; then
+  old_LDFLAGS="$LDFLAGS"
+  LDFLAGS="$LDFLAGS -Wl,--as-needed"
+  AC_MSG_CHECKING([whether linker supports --as-needed])
+  AC_LINK_IFELSE([int main(void) { return 0; }],
+    [AC_MSG_RESULT([yes])],
+    [AC_MSG_RESULT([no])
+     LDFLAGS="$old_LDFLAGS"])
+fi
+dnl Pick good warning flags for gcc
+if test x"$GCC" = xyes; then
+  AC_MSG_CHECKING([for working warning switches])
+  good_CFLAGS="$CFLAGS"
+  warnings=""
+  flags="-Wall -Wextra"
+  # turn off noise from Wextra
+  flags="$flags -Wno-unused-parameter -Wno-missing-field-initializers"
+  # Wextra does not turn those on?
+  flags="$flags -Wmissing-prototypes -Wpointer-arith -Wendif-labels"
+  flags="$flags -Wdeclaration-after-statement -Wold-style-definition"
+  flags="$flags -Wstrict-prototypes -Wundef -Wformat -Wnonnull -Wstrict-overflow"
+  for f in $flags; do
+    CFLAGS="$good_CFLAGS $warnings $f"
+    AC_COMPILE_IFELSE([void foo(void){}], [warnings="$warnings $f"])
+  done
+  CFLAGS="$good_CFLAGS $warnings"
+  AC_MSG_RESULT([done])
+fi
+# autoconf does not want to find 'install', if not using automake...
+INSTALL=install
+BININSTALL="$INSTALL"
+AC_SUBST(INSTALL)
+AC_SUBST(BININSTALL)
+AC_CHECK_TOOL([STRIP], [strip])
+AC_CHECK_TOOL([AR], [ar])
+])
+
+
+dnl
+dnl AC_USUAL_TYPE_CHECK: Basic types for C
+dnl
+AC_DEFUN([AC_USUAL_TYPE_CHECK], [
+AC_C_INLINE
+AC_C_BIGENDIAN
+AC_SYS_LARGEFILE
+AC_TYPE_PID_T
+AC_TYPE_UID_T
+AC_TYPE_SIZE_T
+]) 
+
+dnl
+dnl  AC_USUAL_HEADER_CHECK:  Basic headers
+dnl
+AC_DEFUN([AC_USUAL_HEADER_CHECK], [
+AC_CHECK_HEADERS([sys/socket.h poll.h sys/poll.h sys/un.h])
+AC_CHECK_HEADERS([arpa/inet.h netinet/in.h netinet/tcp.h])
+AC_CHECK_HEADERS([sys/param.h sys/uio.h libgen.h pwd.h grp.h])
+AC_CHECK_HEADERS([sys/wait.h sys/mman.h syslog.h netdb.h])
+dnl ucred.h may have prereqs
+AC_CHECK_HEADERS([ucred.h sys/ucred.h], [], [], [
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+])])
+
+
+dnl
+dnl  AC_USUAL_FUNCTION_CHECK:  Basic functions
+dnl
+AC_DEFUN([AC_USUAL_FUNCTION_CHECK], [
+### Functions provided by usual/compat if missing
+AC_CHECK_FUNCS(basename strlcpy strlcat getpeereid sigaction)
+AC_CHECK_FUNCS(inet_ntop poll getline)
+### Functions provided only on win32
+AC_CHECK_FUNCS(locatime_r recvmsg sendmsg)
+### Functions used by libusual itself
+AC_CHECK_FUNCS(syslog mmap recvmsg sendmsg getpeerucred)
+### win32: link with ws2_32
+AC_SEARCH_LIBS(WSAGetLastError, ws2_32)
+])
+
+dnl
+dnl  AC_USUAL_CASSERT:  --enable-cassert switch to set macro CASSERT
+dnl
+AC_DEFUN([AC_USUAL_CASSERT], [
+AC_ARG_ENABLE(cassert, AC_HELP_STRING([--enable-cassert],[turn on assert checking in code]))
+AC_MSG_CHECKING([whether to enable asserts])
+if test "$enable_cassert" = "yes"; then
+  AC_DEFINE(CASSERT, 1, [Define to enable assert checking])
+  AC_MSG_RESULT([yes])
+else
+  AC_MSG_RESULT([no])
+fi
+])
+
+
+dnl
+dnl  AC_USUAL_WERROR:  --enable-werror switch to turn warnings into errors
+dnl
+AC_DEFUN([AC_USUAL_WERROR], [
+AC_ARG_ENABLE(werror, AC_HELP_STRING([--enable-werror],[add -Werror to CFLAGS]))
+AC_MSG_CHECKING([whether to fail on warnings])
+if test "$enable_werror" = "yes"; then
+  CFLAGS="$CFLAGS -Werror"
+  AC_MSG_RESULT([yes])
+else
+  AC_MSG_RESULT([no])
+fi
+])
+
+
+dnl
+dnl  AC_USUAL_DEBUG:  --disable-debug switch to strip binary
+dnl
+AC_DEFUN([AC_USUAL_DEBUG], [
+AC_ARG_ENABLE(debug,
+  AC_HELP_STRING([--disable-debug],[strip binary]),
+  [], [enable_debug=yes])
+AC_MSG_CHECKING([whether to build debug binary])
+if test "$enable_debug" = "yes"; then
+  LDFLAGS="-g $LDFLAGS"
+  BININSTALL="$INSTALL"
+  AC_MSG_RESULT([yes])
+else
+  BININSTALL="$INSTALL -s"
+  AC_MSG_RESULT([no])
+fi
+AC_SUBST(enable_debug)
+])
+
+
index b44361ab53fd0275045694c134de7dff9982f13e..0378facbd953449c44a0905d3a842e8704fb90d3 100644 (file)
@@ -43,7 +43,7 @@
  */
 
 
-#include "aatree.h"
+#include <usual/aatree.h>
 
 #include <stddef.h>   /* for NULL */
 
index 8ff779a298c59887951dafd3a37223d36882aaef..821a1ea6d06036a9679bd58951e718609cbc8baa 100644 (file)
@@ -19,6 +19,8 @@
 #ifndef _USUAL_AATREE_H_
 #define _USUAL_AATREE_H_
 
+#include <usual/base.h>
+
 struct AATree;
 struct AANode;
 
index 90bcee541d88f168c6d665f6f28259aed4dc3ef2..f9f27b0a54e6c29d43d5045b3c427d4cf208ab66 100644 (file)
@@ -19,6 +19,7 @@
 #ifndef _USUAL_BASE_H_
 #define _USUAL_BASE_H_
 
+#include <usual/config.h>
 
 #include <sys/types.h>
 #include <stddef.h>
diff --git a/usual/compat.c b/usual/compat.c
new file mode 100644 (file)
index 0000000..b8a332e
--- /dev/null
@@ -0,0 +1,388 @@
+
+#include <usual/compat.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_UCRED_H
+#include <ucred.h>
+#endif
+#ifdef HAVE_SYS_UCRED_H
+#include <sys/ucred.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+#include <usual/logging.h>
+
+#ifndef HAVE_GETLINE
+/*
+ * Read line from FILE with dynamic allocation.
+ */
+int getline(char **line_p, size_t *size_p, void *_f)
+{
+       FILE *f = _f;
+       char *p;
+       int len = 0;
+
+       if (!*line_p || *size_p < 128) {
+               p = realloc(*line_p, 512);
+               if (!p) return -1;
+               *line_p = p;
+               *size_p = 512;
+       }
+
+       while (1) {
+               p = fgets(*line_p + len, *size_p - len, f);
+               if (!p)
+                       return len ? len : -1;
+               len += strlen(p);
+               if ((*line_p)[len - 1] == '\n')
+                       return len;
+               p = realloc(*line_p, *size_p * 2);
+               if (!p)
+                       return -1;
+               *line_p = p;
+               *size_p *= 2;
+       }
+}
+#endif
+
+#ifndef HAVE_GETPEEREID
+/*
+ * Get other side's uid for UNIX socket.
+ *
+ * Standardise on getpeereid() from BSDs.
+ */
+int getpeereid(int fd, uid_t *uid_p, gid_t *gid_p)
+{
+#ifdef SO_PEERCRED
+       struct ucred cred;
+       socklen_t len = sizeof(cred);
+       if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) >= 0) {
+               *uid_p = cred.uid;
+               *gid_p = cred.gid;
+               return 0;
+       }
+#else /* !SO_PEERCRED */
+#ifdef HAVE_GETPEERUCRED
+       ucred_t *cred = NULL;
+       if (getpeerucred(fd, &cred) >= 0) {
+               *uid_p = ucred_geteuid(cred);
+               *gid_p = ucred_getegid(cred);
+               ucred_free(cred);
+               if (*uid_p >= 0 && *gid_p >= 0)
+                       return 0;
+       }
+#else
+       errno = ENOSYS;
+#endif /* HAVE_GETPEERUCRED */
+#endif /* !SO_PEERCRED */
+       return -1;
+}
+#endif
+
+#ifndef HAVE_BASENAME
+const char *basename(const char *path)
+{
+       const char *p;
+       if (path == NULL || path[0] == 0)
+               return ".";
+       if ((p = strrchr(path, '/')) != NULL)
+               return p[1] ? p + 1 : p;
+       return path;
+}
+#endif
+
+#ifndef HAVE_INET_NTOP
+const char *inet_ntop(int af, const void *src, char *dst, int cnt)
+{
+       const unsigned char *p = src;
+       if (af != AF_INET)
+               return NULL;
+       snprintf(dst, cnt, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+       return dst;
+}
+#endif
+
+#ifndef HAVE_POLL
+/*
+ * Emulate poll() with select()
+ */
+#include <sys/time.h>
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+/*
+ * dynamic buffer for fd_set to avoid depending on FD_SETSIZE
+ */
+
+struct fd_buf {
+       fd_set *set;
+       int alloc_bytes;
+};
+
+static void fdbuf_zero(struct fd_buf *buf)
+{
+       if (buf->set)
+               memset(buf->set, 0, buf->alloc_bytes);
+}
+
+static bool fdbuf_resize(struct fd_buf *buf, int fd)
+{
+       /* get some extra room for quaranteed alignment */
+       int need_bytes = fd/8 + 32;
+       /* default - 2048 fds */
+       int alloc = 256;
+       unsigned char *ptr;
+
+       if (buf->alloc_bytes < need_bytes)
+       {
+               while (alloc < need_bytes)
+                       alloc *= 2;
+
+               if (!buf->set)
+                       ptr = malloc(alloc);
+               else
+                       ptr = realloc(buf->set, alloc);
+
+               if (!ptr)
+                       return false;
+
+               /* clean new area */
+               memset(ptr + buf->alloc_bytes, 0, alloc - buf->alloc_bytes);
+
+               buf->set = (fd_set *)ptr;
+               buf->alloc_bytes = alloc;
+       }
+       return true;
+}
+
+int poll(struct pollfd *fds, nfds_t nfds, int timeout_ms)
+{
+       static struct fd_buf readfds = { NULL, 0 };
+       static struct fd_buf writefds = { NULL, 0 };
+
+       struct pollfd *pf;
+       int res, fd_max = 0;
+       struct timeval *tv = NULL;
+       struct timeval tvreal;
+       unsigned i;
+
+       /* convert timeout_ms to timeval */
+       if (timeout_ms >= 0)
+       {
+               tvreal.tv_sec = timeout_ms / 1000;
+               tvreal.tv_usec = (timeout_ms % 1000) * 1000;
+               tv = &tvreal;
+       } else if (timeout_ms < -1)
+               goto err_inval;
+
+       /*
+        * Convert pollfds to fd sets.
+        */
+       fdbuf_zero(&readfds);
+       fdbuf_zero(&writefds);
+       for (i = 0; i < nfds; i++)
+       {
+               pf = fds + i;
+               if (pf->fd < 0)
+                       goto err_badf;
+
+               /* sets must be equal size */
+               if (!fdbuf_resize(&readfds, pf->fd))
+                       goto err_nomem;
+               if (!fdbuf_resize(&writefds, pf->fd))
+                       goto err_nomem;
+
+               if (pf->events & POLLIN)
+                       FD_SET((unsigned)pf->fd, readfds.set);
+               if (pf->events & POLLOUT)
+                       FD_SET((unsigned)pf->fd, writefds.set);
+               if (pf->fd > fd_max)
+                       fd_max = pf->fd;
+       }
+
+       res = select(fd_max + 1, readfds.set, writefds.set, NULL, tv);
+       if (res <= 0)
+               return res;
+
+       /*
+        * select() and poll() count fd-s differently,
+        * need to recount them here.
+        */
+       res = 0;
+
+       for (i = 0; i < nfds; i++)
+       {
+               pf = fds + i;
+               pf->revents = 0;
+               if ((pf->events & POLLIN) && FD_ISSET(pf->fd, readfds.set))
+                       pf->revents |= POLLIN;
+               if ((pf->events & POLLOUT) && FD_ISSET(pf->fd, writefds.set))
+                       pf->revents |= POLLOUT;
+               if (pf->revents)
+                       res += 1;
+       }
+       return res;
+
+err_nomem:
+       errno = ENOMEM;
+       return -1;
+
+err_badf:
+       errno = EBADF;
+       return -1;
+err_inval:
+       errno = EINVAL;
+       return -1;
+}
+
+#endif /* PLPROXY_POLL_COMPAT */
+
+#ifndef HAVE_SIGACTION
+#include <signal.h>
+int sigaction(int sig, const struct sigaction *sa, struct sigaction *old)
+{
+       old->sa_handler = signal(sig, sa->sa_handler);
+       if (old->sa_handler == SIG_ERR)
+               return -1;
+       return 0;
+}
+#endif
+
+#ifdef WIN32
+const char *win32_strerror(int e)
+{
+       static char buf[1024];
+       FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, e,
+                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                     buf, sizeof(buf), NULL);
+       return buf;
+}
+
+void win32_eventlog(int level, const char *fmt, ...)
+{
+       static HANDLE evtHandle = INVALID_HANDLE_VALUE;
+       int elevel;
+       char buf[1024];
+       const char *strlist[1] = { buf };
+       va_list ap;
+
+       va_start(ap, fmt);
+       vsnprintf(buf, sizeof(buf), fmt, ap);
+       va_end(ap);
+
+       switch (level) {
+       case LOG_CRIT:
+       case LOG_ERR:
+               elevel = EVENTLOG_ERROR_TYPE;
+               break;
+       case LOG_WARNING:
+               elevel = EVENTLOG_WARNING_TYPE;
+               break;
+       default:
+               elevel = EVENTLOG_INFORMATION_TYPE;
+       }
+
+       if (evtHandle == INVALID_HANDLE_VALUE) {
+               evtHandle = RegisterEventSource(NULL, cf_syslog_ident);
+               if (evtHandle == NULL || evtHandle == INVALID_HANDLE_VALUE) {
+                       evtHandle = INVALID_HANDLE_VALUE;
+                       return;
+               }
+       }
+       ReportEvent(evtHandle, elevel, 0, 0, NULL, 1, 0, strlist, NULL);
+}
+
+/* create local TCP socket, idea from libevent/Tor */
+int win32_socketpair(int d, int typ, int proto, int sv[2])
+{
+       int list = -1, s1 = -1, s2 = -1;
+       struct sockaddr_in sa1, sa2;
+       socklen_t slen = sizeof(sa1);
+       int res;
+
+       if (d != AF_INET && d != AF_UNIX)
+               goto err_inval;
+       if (proto || !sv)
+               goto err_inval;
+
+       /* prepare sockaddr for bind */
+       memset(&sa1, 0, sizeof(sa1));
+       sa1.sin_family = AF_INET;
+       sa1.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+       sa1.sin_port = htons(0);
+
+       /* create listen socket */
+       list = socket(AF_INET, typ, 0);
+       if (list == -1)
+               return -1;
+       res = bind(list, (struct sockaddr *)&sa1, sizeof(sa1));
+       if (res == -1)
+               goto failed;
+       res = listen(list, 1);
+       if (res == -1)
+               goto failed;
+
+       /* read listen port */
+       res = getsockname(list, (struct sockaddr *)&sa1, &slen);
+       if (res == -1 || slen != sizeof(sa1))
+               goto failed;
+
+       /* connect to it */
+       s1 = socket(AF_INET, typ, 0);
+       if (s1 == -1)
+               goto failed;
+       res = connect(s1, (struct sockaddr *)&sa1, sizeof(sa1));
+       if (res == -1)
+               goto failed;
+
+       /* and accept from other end */
+       s2 = accept(list, (struct sockaddr *)&sa2, &slen);
+       if (s2 == -1 || slen != sizeof(sa2))
+               goto failed;
+
+       /* sanity check */
+       res = getsockname(s1, (struct sockaddr *)&sa1, &slen);
+       if (res == -1 || slen != sizeof(sa1))
+               goto failed;
+       if (sa1.sin_port != sa2.sin_port)
+               goto failed;
+
+       closesocket(list);
+       sv[0] = s1;
+       sv[1] = s2;
+       return 0;
+
+failed:
+       errno = (res == -1) ? WSAGetLastError() : EFAULT;
+       if (list != -1) closesocket(list);
+       if (s1 != -1) closesocket(s1);
+       if (s2 != -1) closesocket(s2);
+       return -1;
+
+err_inval:
+       errno = EINVAL;
+       return -1;
+}
+
+#endif
+
diff --git a/usual/compat.h b/usual/compat.h
new file mode 100644 (file)
index 0000000..46f5196
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef _USUAL_COMPAT_H_
+#define _USUAL_COMPAT_H_
+
+#include <usual/base.h>
+
+#ifdef WIN32
+#include <usual/win32.h>
+#endif
+
+#if !defined(HAVE_GETLINE)
+#define getline(a,b,c) compat_getline(a,b,c)
+int getline(char **line_p, size_t *size_p, void *f);
+#endif
+
+
+#if !defined(HAVE_POLL)
+#define POLLIN         (1 << 0)
+#define POLLOUT                (1 << 1)
+#define POLLHUP                (1 << 2)
+#define POLLPRI                (1 << 3)
+#define POLLNVAL       (1 << 4)
+#define POLLERR                (1 << 5)
+#define poll(a,b,c)    compat_poll(a,b,c)
+struct pollfd {
+       int fd;
+       short events;
+       short revents;
+};
+typedef unsigned long nfds_t;
+int poll(struct pollfd *fds, nfds_t nfds, int timeout_ms);
+#endif
+
+
+#ifndef HAVE_INET_NTOP
+#define inet_ntop(a,b,c,d) compat_inet_ntop(a,b,c,d)
+const char *inet_ntop(int af, const void *src, char *dst, int cnt);
+#endif
+
+
+#ifndef HAVE_GETPEEREID
+#define getpeereid(a,b,c) compat_getpeereid(a,b,c)
+int getpeereid(int fd, uid_t *uid_p, gid_t *gid_p);
+#endif
+
+
+#ifndef HAVE_BASENAME
+#define basename(a) compat_basename(a)
+const char *basename(const char *path);
+#endif
+
+
+#ifndef HAVE_SIGACTION
+#define SA_SIGINFO 1
+#define SA_RESTART 2
+typedef struct siginfo_t siginfo_t;
+struct sigaction {
+       union {
+               void     (*sa_handler)(int);
+               void     (*sa_sigaction)(int, siginfo_t *, void *);
+       };
+       int sa_flags;
+       int sa_mask;
+};
+#define sigemptyset(s)
+#define sigfillset(s)
+#define sigaddset(s, sig)
+#define sigdelset(s, sig)
+#define sigaction(a,b,c) compat_sigaction(a,b,c)
+int sigaction(int sig, const struct sigaction *sa, struct sigaction *old);
+#endif
+
+#ifdef WIN32
+#define socketpair(a,b,c,d) win32_socketpair(a,b,c,d)
+int win32_socketpair(int d, int typ, int proto, int sv[2]);
+#endif
+
+#endif
+
index 2f3b0f09e755e32db33945a3ba5749fec9c13356..812ddafccad395664c30bb2f749875cf704df87a 100644 (file)
@@ -30,6 +30,7 @@
 #include <stdio.h>
 
 #include <usual/logging.h>
+#include <usual/compat.h>
 
 /*
  * pidfile management.
index a79d20f1a40524b365495c3bf9effed1f61969d7..3fbe175682abbf8ad368bf5142efd0a48c4ae68d 100644 (file)
@@ -19,7 +19,7 @@
 #ifndef _USUAL_DAEMON_H_
 #define _USUAL_DAEMON_H_
 
-#include <stdbool.h>
+#include <usual/base.h>
 
 void daemonize(const char *pidfile, bool go_background);
 
index 870ae79eb576f01885c97b3d58c9db112d0c4ff0..8f31e901924e9fd35c62516ad13b86efe93ad978 100644 (file)
  * For sitations where full libevent is not necessary.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <usual/event.h>
 
+#include <usual/base.h>
+#include <usual/compat.h>
+
+#ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
+#endif
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
+
+
 #include <errno.h>
 #include <signal.h>
 #include <string.h>
 #include <unistd.h>
-#include <poll.h>
 #include <stdlib.h>
 
 #include <usual/statlist.h>
 #include <usual/socket.h>
 #include <usual/alloc.h>
 
+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL 0
+#endif
+
 /* max number of signals we care about */
 #define MAX_SIGNAL 32
 
@@ -130,15 +139,11 @@ static void ev_dbg(struct event *ev, const char *s, ...)
        va_list ap;
        char buf[1024], tval[128];
        const char *typ = (ev->flags & EV_SIGNAL) ? "sig" : "fd";
-       struct timeval tv;
 
        va_start(ap, s);
        vsnprintf(buf, sizeof(buf), s, ap);
        va_end(ap);
 
-       tv.tv_sec = ev->timeout_val / USEC;
-       tv.tv_usec = ev->timeout_val % USEC;
-
        log_noise("event %s %d (flags=%s%s%s%s%s) [%s]: %s", typ, ev->fd,
               (ev->flags & EV_ACTIVE) ? "A" : "",
               (ev->flags & EV_PERSIST) ? "P" : "",
@@ -146,7 +151,7 @@ static void ev_dbg(struct event *ev, const char *s, ...)
               (ev->flags & EV_READ) ? "R" : "",
               (ev->flags & EV_WRITE) ? "W" : "",
               (ev->flags & EV_TIMEOUT)
-              ? format_time_ms(&tv, tval, sizeof(tval))
+              ? format_time_ms(ev->timeout_val, tval, sizeof(tval))
               : "-",
               buf);
 }
index b4e14f905f0100845bcca107a041d0de9982036c..2132a2eb0f5fad6f81ace4f86f144b8a8a3ab82b 100644 (file)
@@ -21,7 +21,6 @@
 
 #include <sys/time.h>
 
-#include <usual/aatree.h>
 #include <usual/list.h>
 #include <usual/time.h>
 
index 7b9b3dcfa4750067d4e84ae03ccbe39ffd4e0d2e..d479031e4ca318668be4967150aa4e11aa6aa8f0 100644 (file)
 
 #include <usual/fileutil.h>
 
+#ifdef HAVE_SYS_MMAN_H
 #include <sys/mman.h>
+#endif
+
 #include <sys/stat.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
 
+#include <usual/compat.h>
+
 /*
  * Load text file into C string.
  */
@@ -102,6 +107,8 @@ ssize_t file_size(const char *fn)
  * Map a file into mem.
  */
 
+#ifdef HAVE_MMAP
+
 int map_file(struct MappedFile *m, const char *fname, int rw)
 {
        struct stat st;
@@ -130,3 +137,4 @@ void unmap_file(struct MappedFile *m)
        m->fd = 0;
 }
 
+#endif
index 308f05b6837fdcbb30c1144b3088b4165b2defcd..2c9ebb159b0a066ec295db4b20fb22a0142b5e33 100644 (file)
 #include <stdlib.h>
 #include <stdarg.h>
 #include <string.h>
-#include <syslog.h>
 #include <unistd.h>
 
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
+#include <usual/compat.h>
 #include <usual/time.h>
 
 int cf_quiet = 0;
@@ -83,7 +87,7 @@ void log_generic(enum LogLevel level, const char *fmt, ...)
        vsnprintf(buf, sizeof(buf), fmt, ap);
        va_end(ap);
 
-       format_time_ms(NULL, timebuf, sizeof(timebuf));
+       format_time_ms(0, timebuf, sizeof(timebuf));
 
        if (!log_file && cf_logfile) {
                static int error_reported = 0;
index 5bf64f7f7857973838f03342fecdc84b9aebcee9..3ad7319956e8fee13dc4d46b0b8ab500f60bd367 100644 (file)
@@ -1,8 +1,7 @@
 #ifndef _USUAL_LOOKUP3_H_
 #define _USUAL_LOOKUP3_H_
 
-#include <stddef.h>
-#include <stdint.h>
+#include <usual/base.h>
 
 uint64_t hash_lookup3(const void *data, size_t len);
 
index 737a7ec45a7a0a7370ef59a2fa989462929d7e3e..190306b3e025e115d586bf2e4f615668c6861d7e 100644 (file)
 #endif
 
 #include <usual/md5.h>
+#include <usual/base.h>
 
 #include <string.h>
-#include <endian.h>
-
-/* check endianess */
-#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN)
-#error "md5.c need sane endian.h"
-#endif
-#if BYTE_ORDER == BIG_ENDIAN
-#define WORDS_BIGENDIAN
-#endif
 
 /*
  * Support functions.
index 759416a06bb3a54d7640305127abe7e8597bef62..685d40933522253002939fcbf6afc50f19a7a808 100644 (file)
@@ -19,7 +19,7 @@
 #ifndef _USUAL_MD5_H_
 #define _USUAL_MD5_H_
 
-#include <stdint.h>
+#include <usual/base.h>
 
 #define MD5_BLOCK_LENGTH       64
 #define MD5_DIGEST_LENGTH      16
index 39e5c8ddaed5f14b6a5093441d0efab35f81b2cc..9ecd1d29c144794a0019d17036f6a0e549ad93f8 100644 (file)
 #include <errno.h>
 #include <string.h>
 #include <stdio.h>
+
+#ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
+#endif
+#ifdef HAVE_SYS_UN_H
 #include <sys/un.h>
+#endif
 
+#include <usual/compat.h>
 #include <usual/logging.h>
 
 int safe_read(int fd, void *buf, int len)
index 2dbcb1b549d8bb5de88a4131f0fdaf132e3a3e4c..4c5f3fee52c8f2cd193b40780e5d5e2c8e50a3c8 100644 (file)
 #ifndef _USUAL_SAFEIO_H_
 #define _USUAL_SAFEIO_H_
 
-#include <usual/base.h>
+#include <usual/compat.h>
 
-#include <sys/types.h>
+
+#ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
+#endif
 
 int safe_read(int fd, void *buf, int len)                       _MUSTCHECK;
 int safe_write(int fd, const void *buf, int len)                _MUSTCHECK;
index 972ce5dadf39f292521aaa828b8fc691db493102..feb255625bf1fe3a70f934e69fa4e1a155d407db 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */ 
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <usual/socket.h>
 
 #include <string.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <unistd.h>
+
+#ifdef HAVE_SYS_UN_H
 #include <sys/un.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
+#endif
+#ifdef HAVE_NETINET_TCP_H
 #include <netinet/tcp.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
+#endif
 
+#include <usual/compat.h>
 #include <usual/logging.h>
 
 /* toggle non-blocking flag */
index fd593a3dc28db92e63553080666369e69237e2f0..ac01382cd541e35c59afcbbf55d6c3cb66086302 100644 (file)
 #define _USUAL_SOCKET_H_
 
 #include <usual/base.h>
+
+#ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
+#endif
 
 bool socket_setup(int sock, bool non_block);
 bool socket_set_nonblocking(int sock, bool non_block);
index 771e4788a8abc8ed7a0a252d0dae9fb375032ee8..077856f62d353ce9e684747954a37b9ac7b4d48c 100644 (file)
@@ -19,6 +19,8 @@
 #ifndef _USUAL_STRING_H_
 #define _USUAL_STRING_H_
 
+#include <usual/base.h>
+
 #include <string.h>
 
 /*
index 3296353b866e9a8bb1b72b30c8725dca50547cb5..8aa9a904ebe3c1f0596441b4cad969b54092c47a 100644 (file)
 #include <time.h>
 #include <stdio.h>
 
-char *format_time_ms(const struct timeval *tv, char *dst, unsigned dstlen)
+#include <usual/compat.h>
+
+char *format_time_ms(usec_t time, char *dst, unsigned dstlen)
 {
        struct tm *tm, tmbuf;
-       struct timeval tvbuf;
+       struct timeval tv;
        time_t sec;
 
-       if (tv == NULL) {
-               gettimeofday(&tvbuf, NULL);
-               tv = &tvbuf;
+       if (!time) {
+               gettimeofday(&tv, NULL);
+       } else {
+               tv.tv_sec = time / USEC;
+               tv.tv_usec = time % USEC;
        }
 
-       sec = tv->tv_sec;
+       sec = tv.tv_sec;
        tm = localtime_r(&sec, &tmbuf);
        snprintf(dst, dstlen, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
                 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
                 tm->tm_hour, tm->tm_min, tm->tm_sec,
-                (int)(tv->tv_usec / 1000));
+                (int)(tv.tv_usec / 1000));
+       return dst;
+}
+
+char *format_time_s(usec_t time, char *dst, unsigned dstlen)
+{
+       time_t s;
+       struct tm tbuf, *tm;
+       if (!time) {
+               struct timeval tv;
+               gettimeofday(&tv, NULL);
+               s = tv.tv_sec;
+       } else {
+               s = time / USEC;
+       }
+       tm = localtime_r(&s, &tbuf);
+       strftime(dst, dstlen, "%Y-%m-%d %H:%M:%S", tm);
        return dst;
 }
 
+
 /* read current time */
 usec_t get_time_usec(void)
 {
index f5634d5d288fa291723cdd79b1886e426d0034f7..09599f615380c4b1e8f235157e29df7ef9106581 100644 (file)
 typedef uint64_t usec_t;
 #define USEC 1000000ULL
 
-char *format_time_ms(const struct timeval *tv, char *dst, unsigned dstlen);
+char *format_time_ms(usec_t time, char *dst, unsigned dstlen);
+char *format_time_s(usec_t time, char *dst, unsigned dstlen);
 
 usec_t get_time_usec(void);
-
 usec_t get_cached_time(void);
 void reset_time_cache(void);
 
diff --git a/usual/win32.h b/usual/win32.h
new file mode 100644 (file)
index 0000000..fd157b5
--- /dev/null
@@ -0,0 +1,332 @@
+#ifndef _USUAL_WIN32_
+#define _USUAL_WIN32_
+
+#define WIN32_LEAN_AND_MEAN
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <time.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define ECONNABORTED WSAECONNABORTED
+#define EMSGSIZE WSAEMSGSIZE
+#define EINPROGRESS WSAEWOULDBLOCK // WSAEINPROGRESS
+
+#undef EAGAIN
+#define EAGAIN WSAEWOULDBLOCK // WSAEAGAIN
+
+/* dummy types / functions */
+#define hstrerror strerror
+#define getuid() (6667)
+#define setsid() getpid()
+#define setgid(x) (-1)
+#define setuid(x) (-1)
+#define fork() (-1)
+#define geteuid() getuid()
+#define setgroups(s, p) (-1)
+
+#define srandom(s) srand(s)
+#define random() rand()
+
+#define in_addr_t   uint32_t
+
+/*
+ * make recvmsg/sendmsg and fd related code compile
+ */
+
+struct iovec {
+       void    *iov_base;      /* Base address. */
+       size_t   iov_len;       /* Length. */
+};
+
+struct msghdr {
+       void         *msg_name;
+       socklen_t     msg_namelen;
+       struct iovec *msg_iov;
+       int           msg_iovlen;
+       void         *msg_control;
+       socklen_t     msg_controllen;
+       int           msg_flags;
+};
+
+struct cmsghdr {
+       socklen_t       cmsg_len;
+       int             cmsg_level;
+       int             cmsg_type;
+};
+
+
+#define SCM_RIGHTS 1
+
+#define CMSG_DATA(cmsg) ((unsigned char *) ((struct cmsghdr *) (cmsg) + 1))
+#define CMSG_ALIGN(len) (((len) + sizeof (size_t) - 1) \
+       & ~(sizeof (size_t) - 1))
+#define CMSG_LEN(len) ((int)(CMSG_ALIGN(sizeof(struct cmsghdr))+(len)))
+#define CMSG_FIRSTHDR(mhdr) \
+       ((mhdr)->msg_controllen >= (int)sizeof(struct cmsghdr) ? \
+       (struct cmsghdr *)(mhdr)->msg_control : \
+       (struct cmsghdr *)NULL)
+#define CMSG_NXTHDR(mhdr, cmsg) \
+       (((cmsg) == NULL) ? CMSG_FIRSTHDR(mhdr) : \
+       (((u_char *)(cmsg) + CMSG_ALIGN((cmsg)->cmsg_len) \
+       + CMSG_ALIGN(sizeof(struct cmsghdr)) > \
+       (u_char *)((mhdr)->msg_control) + (mhdr)->msg_controllen) ? \
+       (struct cmsghdr *)NULL : \
+       (struct cmsghdr *)((u_char *)(cmsg) + CMSG_ALIGN((cmsg)->cmsg_len))))
+#define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr))+CMSG_ALIGN(len))
+
+/*
+ * unify WSAGetLastError() with errno.
+ */
+
+static inline int ewrap(int res) {
+       if (res < 0)
+               errno = WSAGetLastError();
+       return res;
+}
+
+/* proper signature for setsockopt */
+static inline int w_setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen)
+{
+       return ewrap(setsockopt(fd, level, optname, optval, optlen));
+}
+#define setsockopt(a,b,c,d,e) w_setsockopt(a,b,c,d,e)
+
+/* proper signature for send */
+static inline ssize_t w_send(int fd, const void *buf, size_t len, int flags) {
+       return ewrap(send(fd, buf, len, flags));
+}
+#define send(a,b,c,d) w_send(a,b,c,d)
+
+/* proper signature for recv */
+static inline ssize_t w_recv(int fd, void *buf, size_t len, int flags) {
+       return ewrap(recv(fd, buf, len, flags));
+}
+#define recv(a,b,c,d) w_recv(a,b,c,d)
+
+#define getsockopt(a,b,c,d,e) ewrap(getsockopt(a,b,c,d,e))
+#define connect(a,b,c) ewrap(connect(a,b,c))
+#define socket(a,b,c) ewrap(socket(a,b,c))
+#define bind(a,b,c) ewrap(bind(a,b,c))
+#define listen(a,b) ewrap(listen(a,b))
+#define accept(a,b,c) ewrap(accept(a,b,c))
+#define getpeername(a,b,c) ewrap(getpeername(a,b,c))
+#define getsockname(a,b,c) ewrap(getsockname(a,b,c))
+#define select(a,b,c,d,e) ewrap(select(a,b,c,d,e))
+
+static inline struct hostent *w_gethostbyname(const char *n) {
+       struct hostent *res = gethostbyname(n);
+       if (!res) errno = WSAGetLastError();
+       return res;
+}
+#define gethostbyname(a) w_gethostbyname(a)
+
+
+/* gettimeoutday() */
+static inline int win32_gettimeofday(struct timeval * tp, void * tzp)
+{
+       FILETIME file_time;
+       SYSTEMTIME system_time;
+       ULARGE_INTEGER ularge;
+       __int64 epoch = 116444736000000000LL;
+
+       GetSystemTime(&system_time);
+       SystemTimeToFileTime(&system_time, &file_time);
+       ularge.LowPart = file_time.dwLowDateTime;
+       ularge.HighPart = file_time.dwHighDateTime;
+
+       tp->tv_sec = (long) ((ularge.QuadPart - epoch) / 10000000L);
+       tp->tv_usec = (long) (system_time.wMilliseconds * 1000);
+
+       return 0;
+}
+#define gettimeofday(a,b) win32_gettimeofday(a,b)
+
+/* make unix socket related code compile */
+struct sockaddr_un {
+       int sun_family;
+       char sun_path[128];
+};
+
+/* getrlimit() */
+#define RLIMIT_NOFILE -1
+struct rlimit {
+       int rlim_cur;
+       int rlim_max;
+};
+static inline int getrlimit(int res, struct rlimit *dst)
+{
+       dst->rlim_cur = dst->rlim_max = -1;
+       return 0;
+}
+
+/* kill is only used to detect if process is running (ESRCH->not) */
+static inline int kill(int pid, int sig)
+{
+       HANDLE hProcess;
+       DWORD exitCode;
+       int ret = 0;
+
+       if (sig != 0) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
+       if (hProcess == NULL) {
+               if (GetLastError() == ERROR_INVALID_PARAMETER)
+                       ret = ESRCH;
+               else
+                       ret = EPERM;
+       } else {
+               /* OpenProcess may succed for exited processes */
+               if (GetExitCodeProcess(hProcess, &exitCode)) {
+                       if (exitCode != STILL_ACTIVE)
+                               ret = ESRCH;
+               }
+               CloseHandle(hProcess);
+       }
+
+       if (ret) {
+               errno = ret;
+               return -1;
+       } else
+               return  0;
+}
+
+/* sendmsg is not used */
+static inline int sendmsg(int s, const struct msghdr *m, int flags)
+{
+       if (m->msg_iovlen != 1) {
+               errno = EINVAL;
+               return -1;
+       }
+       return send(s, m->msg_iov[0].iov_base,
+                   m->msg_iov[0].iov_len, flags);
+}
+
+/* recvmsg() is, but only with one iov */
+static inline int recvmsg(int s, struct msghdr *m, int flags)
+{
+       if (m->msg_iovlen != 1) {
+               errno = EINVAL;
+               return -1;
+       }
+       if (m->msg_controllen)
+               m->msg_controllen = 0;
+       return recv(s, m->msg_iov[0].iov_base,
+                   m->msg_iov[0].iov_len, flags);
+}
+
+/* dummy getpwnam() */
+struct passwd {
+       char *pw_name;
+       char *pw_passwd;
+       int pw_uid;
+       int pw_gid;
+};
+static inline const struct passwd * getpwnam(const char *u) { return NULL; }
+
+/*
+ * fcntl
+ */
+
+#define F_GETFD 1
+#define F_SETFD 2
+#define F_GETFL 3
+#define F_SETFL 4
+#define O_NONBLOCK 1
+#define FD_CLOEXEC HANDLE_FLAG_INHERIT
+
+static inline int fcntl(int fd, int cmd, long arg)
+{
+       ULONG lval;
+       DWORD dval;
+       switch (cmd) {
+       case F_GETFD:
+               if (GetHandleInformation((HANDLE)fd, &dval))
+                       return dval;
+               errno = EINVAL;
+               return -1;
+       case F_SETFD:
+               /* set FD_CLOEXEC */
+               if (SetHandleInformation((HANDLE)fd, FD_CLOEXEC, arg))
+                       return 0;
+               errno = EINVAL;
+               return -1;
+       case F_GETFL:
+               /* O_NONBLOCK? */
+               return 0;
+       case F_SETFL:
+               /* set O_NONBLOCK */
+               lval = (arg & O_NONBLOCK) ? 1 : 0;
+               if (ioctlsocket(fd, FIONBIO, &lval) == SOCKET_ERROR) {
+                       errno = WSAGetLastError();
+                       return -1;
+               }
+               return 0;
+       default:
+               errno = EINVAL;
+               return -1;
+       }
+}
+
+/*
+ * syslog
+ */
+
+#define LOG_EMERG      0
+#define LOG_ALERT      1
+#define LOG_CRIT       2
+#define LOG_ERR                3
+#define LOG_WARNING    4
+#define LOG_NOTICE     5
+#define LOG_INFO       6
+#define LOG_DEBUG      7
+
+#define LOG_PID 0
+
+#define LOG_KERN 0
+#define LOG_USER 0
+#define LOG_MAIL 0
+#define LOG_DAEMON 0
+#define LOG_AUTH 0
+#define LOG_SYSLOG 0
+#define LOG_LPR 0
+#define LOG_NEWS 0
+#define LOG_UUCP 0
+#define LOG_CRON 0
+#define LOG_AUTHPRIV 0
+#define LOG_FTP 0
+#define LOG_LOCAL0 0
+#define LOG_LOCAL1 0
+#define LOG_LOCAL2 0
+#define LOG_LOCAL3 0
+#define LOG_LOCAL4 0
+#define LOG_LOCAL5 0
+#define LOG_LOCAL6 0
+#define LOG_LOCAL7 0
+
+static inline void openlog(const char *ident, int option, int facility) {}
+static inline void closelog(void) {}
+void win32_eventlog(int priority, const char *format, ...);
+#define syslog win32_eventlog
+
+static inline struct tm *localtime_r(const time_t *tp, struct tm *buf)
+{
+       struct tm *r = localtime(tp);
+       *buf = *r;
+       return buf;
+}
+
+const char *win32_strerror(int e);
+static inline const char *w_strerror(int e) {
+       if (e > 900)
+               return win32_strerror(e);
+       return strerror(e);
+}
+#define strerror(x) w_strerror(x)
+
+#endif