[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#778919: unblock: nbd/1:3.8-3



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Hi,

Please unblock package nbd

I had uploaded it way back in october, around the freeze, and had
thought that it had migrated. Yesterday, I noticed (to my surprise) that
this did not happen. I suppose I should've paid more attention.

The majority of the changes are related to supporting root-on-NBD
properly in conjunction with systemd, so I would really like to get this
migrated. I realize that it's a bit late now, but since the package has
been in unstable with no problems since pretty much october, I doubt
there's going to be a major regression.

debdiff is attached. There is a bit of irrelevant noise in there, due to
the fact that my upstream build directory and my debian build directory
are, really, one and the same place (modulo a git branch), and that I
sometimes forget to ensure that everything is really clean. Yes, I may
need to review how I build packages a bit. To guide you through the
noise a bit, here's an annotated diffstat:

 aclocal.m4                               |   60 

autotools update, no nbd-specific changes

 cliserv.c.gcov                           |   81 

uncleanliness

 config.guess                             |  192 --
 config.sub                               |   23 
 configure                                |    5 

autotools

 debian/preinst                           |   42 
 debian/prerm                             |   37 

explanation in changelog (these used to do something in previous
versions of nbd, but this is no longer the case, and what was left was
nothing more than the debhelper templates)

 gznbd/Makefile.in                        |  641 +++++++
 libcliserv.la                            |   41 

Build artifacts from another branch

 nbd-3.8/debian/changelog                 |   26 
 nbd-3.8/debian/nbd-client.initramfs-hook |    2 
 nbd-3.8/debian/nbd-client.initrd         |    3 

Not sure why debdiff prepends "nbd-3.8" here and not for the other
files, but these contain the changes required for proper
root-on-NBD-with-systemd support

 nbd-3.8/debian/nbd-server.init.d         |    7 

Add a "reload" target (wishlist bug)

 nbd-client.c.gcov                        |  679 +++++++
 nbd-server.c.gcov                        | 2809 +++++++++++++++++++++++++++++++

Uncleanliness

 test.conf                                |    4 
 tests/run/testlib.sh                     |   42 

Artifacts from another branch.

 17 files changed, 4430 insertions(+), 264 deletions(-)

If you prefer, I can do another upload with the junk removed. Either way
works for me.

unblock nbd/1:3.8-3

Thanks,

-- System Information:
Debian Release: 8.0
  APT prefers unstable
  APT policy: (500, 'unstable'), (500, 'testing'), (500, 'stable'), (500, 'oldstable'), (1, 'experimental')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 3.16.0-4-amd64 (SMP w/4 CPU cores)
Locale: LANG=nl_BE.UTF-8, LC_CTYPE=nl_BE.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
diff -u nbd-3.8/debian/changelog nbd-3.8/debian/changelog
--- nbd-3.8/debian/changelog
+++ nbd-3.8/debian/changelog
@@ -1,3 +1,29 @@
+nbd (1:3.8-3) unstable; urgency=medium
+
+  * Brown paper bag release.
+  * Add missing double-semicolon (whoops). Closes: #766888.
+
+ -- Wouter Verhelst <wouter@debian.org>  Wed, 29 Oct 2014 23:44:25 +0100
+
+nbd (1:3.8-2) unstable; urgency=medium
+
+  * The "deal with 727708" release
+  * Add some initial support for systemd: Call nbd-client with the
+    -systemd-mark option from initramfs, to make sure root-on-NBD continues
+    working properly even if the user is running systemd. Still leaves
+    writing a systemd generator mumble mumble thing, but that's for
+    later.
+  * debian/pre{inst,rm}: remove, no content
+  * debian/nbd-client.initr{amfs-hook,d}: don't force-load nbd, instead
+    only load the module if we're actually doing root-on-NBD.
+  * debian/nbd-server.init.d: add reload target, which sends SIGHUP to
+    nbd-server. This allows partial reconfiguration from the config
+    file; however, since it doesn't change existing configurations nor
+    remove configurations that are no longer active, it's not a full
+    reload, so leave force-reload as restart. LP:1359799
+
+ -- Wouter Verhelst <wouter@debian.org>  Mon, 19 May 2014 08:41:54 +0200
+
 nbd (1:3.8-1) unstable; urgency=medium
 
   * New upstream release.
diff -u nbd-3.8/debian/nbd-client.initramfs-hook nbd-3.8/debian/nbd-client.initramfs-hook
--- nbd-3.8/debian/nbd-client.initramfs-hook
+++ nbd-3.8/debian/nbd-client.initramfs-hook
@@ -10,5 +10,5 @@
 . /usr/share/initramfs-tools/hook-functions
 
-force_load nbd
+manual_add_modules nbd
 auto_add_modules net
 copy_exec /sbin/nbd-client /sbin
diff -u nbd-3.8/debian/nbd-client.initrd nbd-3.8/debian/nbd-client.initrd
--- nbd-3.8/debian/nbd-client.initrd
+++ nbd-3.8/debian/nbd-client.initrd
@@ -31,6 +31,7 @@
 
 log_begin_msg "Setting up nbd-client"
 
+modprobe nbd
 wait_for_udev
 configure_networking
 
@@ -104,7 +105,7 @@
 
 # Support defining an alternate launch script with env variable NBDCLIENT.
 NBDCLIENT=${NBDCLIENT:-/sbin/nbd-client}
-$NBDCLIENT $nbdsrv ${nbdpath:+-N} $nbdpath $nbdport $nbdrootdev -swap -persist
+$NBDCLIENT $nbdsrv ${nbdpath:+-N} $nbdpath $nbdport $nbdrootdev -swap -persist -systemd-mark
 
 # This should be removed once the cfq scheduler no longer deadlocks nbd
 # devices
diff -u nbd-3.8/debian/nbd-server.init.d nbd-3.8/debian/nbd-server.init.d
--- nbd-3.8/debian/nbd-server.init.d
+++ nbd-3.8/debian/nbd-server.init.d
@@ -40,6 +40,13 @@
 	start-stop-daemon --stop --quiet --exec /bin/nbd-server --oknodo --pidfile /var/run/nbd-server.pid --retry 1
 	echo " $NAME."
 	;;
+    reload)
+    	echo -n "Reloading $DESC:"
+	if [ -f /var/run/nbd-server.pid ]
+	then
+		kill -HUP $(cat /var/run/nbd-server.pid)
+	fi
+	;;
     restart|force-reload)
 	echo "Restarting the $DESC is pretty harsh on clients still using it."
 	echo -n "waiting 5 seconds..."
reverted:
--- nbd-3.8/debian/preinst
+++ nbd-3.8.orig/debian/preinst
@@ -1,42 +0,0 @@
-#! /bin/sh
-# preinst script for nbd
-#
-# see: dh_installdeb(1)
-
-set -e
-
-# summary of how this script can be called:
-#        * <new-preinst> `install'
-#        * <new-preinst> `install' <old-version>
-#        * <new-preinst> `upgrade' <old-version>
-#        * <old-preinst> `abort-upgrade' <new-version>
-#
-# For details see /usr/share/doc/packaging-manual/
-
-case "$1" in
-    install|upgrade)
-#        if [ "$1" = "upgrade" ]
-#        then
-#            start-stop-daemon --stop --quiet --oknodo  \
-#                --pidfile /var/run/nbd.pid  \
-#                --exec /usr/sbin/nbd 2>/dev/null || true
-#        fi
-    ;;
-
-    abort-upgrade)
-    ;;
-
-    *)
-        echo "preinst called with unknown argument \`$1'" >&2
-        exit 0
-    ;;
-esac
-
-# dh_installdeb will replace this with shell code automatically
-# generated by other debhelper scripts.
-
-#DEBHELPER#
-
-exit 0
-
-
reverted:
--- nbd-3.8/debian/prerm
+++ nbd-3.8.orig/debian/prerm
@@ -1,37 +0,0 @@
-#! /bin/sh
-# prerm script for nbd
-#
-# see: dh_installdeb(1)
-
-set -e
-
-# summary of how this script can be called:
-#        * <prerm> `remove'
-#        * <old-prerm> `upgrade' <new-version>
-#        * <new-prerm> `failed-upgrade' <old-version>
-#        * <conflictor's-prerm> `remove' `in-favour' <package> <new-version>
-#        * <deconfigured's-prerm> `deconfigure' `in-favour'
-#          <package-being-installed> <version> `removing'
-#          <conflicting-package> <version>
-# for details, see /usr/share/doc/packaging-manual/
-
-case "$1" in
-    remove|upgrade|deconfigure)
-#       install-info --quiet --remove /usr/info/nbd.info.gz
-        ;;
-    failed-upgrade)
-        ;;
-    *)
-        echo "prerm called with unknown argument \`$1'" >&2
-        exit 0
-    ;;
-esac
-
-# dh_installdeb will replace this with shell code automatically
-# generated by other debhelper scripts.
-
-#DEBHELPER#
-
-exit 0
-
-
only in patch2:
unchanged:
--- nbd-3.8.orig/aclocal.m4
+++ nbd-3.8/aclocal.m4
@@ -115,13 +115,10 @@
 main ()
 {
   unsigned int major, minor, micro;
-  char *tmp_version;
 
   fclose (fopen ("conf.glibtest", "w"));
 
-  /* HP/UX 9 (%@#!) writes to sscanf strings */
-  tmp_version = g_strdup("$min_glib_version");
-  if (sscanf(tmp_version, "%u.%u.%u", &major, &minor, &micro) != 3) {
+  if (sscanf("$min_glib_version", "%u.%u.%u", &major, &minor, &micro) != 3) {
      printf("%s, bad version string\n", "$min_glib_version");
      exit(1);
    }
@@ -8997,6 +8994,61 @@
 fi[]dnl
 ])# PKG_CHECK_MODULES
 
+
+# PKG_INSTALLDIR(DIRECTORY)
+# -------------------------
+# Substitutes the variable pkgconfigdir as the location where a module
+# should install pkg-config .pc files. By default the directory is
+# $libdir/pkgconfig, but the default can be changed by passing
+# DIRECTORY. The user can override through the --with-pkgconfigdir
+# parameter.
+AC_DEFUN([PKG_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+    [pkg-config installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([pkgconfigdir],
+    [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
+    [with_pkgconfigdir=]pkg_default)
+AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+]) dnl PKG_INSTALLDIR
+
+
+# PKG_NOARCH_INSTALLDIR(DIRECTORY)
+# -------------------------
+# Substitutes the variable noarch_pkgconfigdir as the location where a
+# module should install arch-independent pkg-config .pc files. By
+# default the directory is $datadir/pkgconfig, but the default can be
+# changed by passing DIRECTORY. The user can override through the
+# --with-noarch-pkgconfigdir parameter.
+AC_DEFUN([PKG_NOARCH_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+    [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([noarch-pkgconfigdir],
+    [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
+    [with_noarch_pkgconfigdir=]pkg_default)
+AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+]) dnl PKG_NOARCH_INSTALLDIR
+
+
+# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
+# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+# -------------------------------------------
+# Retrieves the value of the pkg-config variable for the given module.
+AC_DEFUN([PKG_CHECK_VAR],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
+
+_PKG_CONFIG([$1], [variable="][$3]["], [$2])
+AS_VAR_COPY([$1], [pkg_cv_][$1])
+
+AS_VAR_IF([$1], [""], [$5], [$4])dnl
+])# PKG_CHECK_VAR
+
 # Copyright (C) 2002-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
only in patch2:
unchanged:
--- nbd-3.8.orig/cliserv.c.gcov
+++ nbd-3.8/cliserv.c.gcov
@@ -0,0 +1,81 @@
+        -:    0:Source:cliserv.c
+        -:    0:Programs:4
+        -:    1:#include <config.h>
+        -:    2:#include <cliserv.h>
+        -:    3:#include <stdio.h>
+        -:    4:#include <syslog.h>
+        -:    5:
+        -:    6:const u64 cliserv_magic = 0x00420281861253LL;
+        -:    7:const u64 opts_magic = 0x49484156454F5054LL;
+        -:    8:const u64 rep_magic = 0x3e889045565a9LL;
+        -:    9:
+       12:   10:void setmysockopt(int sock) {
+       12:   11:	int size = 1;
+        -:   12:#if 0
+        -:   13:	if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) < 0)
+        -:   14:		 INFO("(no sockopt/1: %m)");
+        -:   15:#endif
+        -:   16:#ifdef	IPPROTO_TCP
+       12:   17:	size = 1;
+       12:   18:	if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &size, sizeof(int)) < 0)
+        -:   19:		 INFO("(no sockopt/2: %m)");
+        -:   20:#endif
+        -:   21:#if 0
+        -:   22:	size = 1024;
+        -:   23:	if (setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &size, sizeof(int)) < 0)
+        -:   24:		 INFO("(no sockopt/3: %m)");
+        -:   25:#endif
+       12:   26:}
+        -:   27:
+        2:   28:void err_nonfatal(const char *s) {
+        -:   29:	char s1[150], *s2;
+        -:   30:
+        2:   31:	strncpy(s1, s, sizeof(s1));
+        2:   32:	if ((s2 = strstr(s, "%m"))) {
+        1:   33:		strcpy(s1 + (s2 - s), strerror(errno));
+        1:   34:		s2 += 2;
+        1:   35:		strcpy(s1 + strlen(s1), s2);
+        -:   36:	}
+        -:   37:#ifndef	sun
+        -:   38:	/* Solaris doesn't have %h in syslog */
+        1:   39:	else if ((s2 = strstr(s, "%h"))) {
+    #####:   40:		strcpy(s1 + (s2 - s), hstrerror(h_errno));
+    #####:   41:		s2 += 2;
+    #####:   42:		strcpy(s1 + strlen(s1), s2);
+        -:   43:	}
+        -:   44:#endif
+        -:   45:
+        2:   46:	s1[sizeof(s1)-1] = '\0';
+        -:   47:#ifdef ISSERVER
+        -:   48:	syslog(LOG_ERR, "%s", s1);
+        -:   49:	syslog(LOG_ERR, "Exiting.");
+        -:   50:#endif
+        2:   51:	fprintf(stderr, "Error: %s\nExiting.\n", s1);
+        2:   52:}
+        -:   53:
+        1:   54:void err(const char *s) {
+        1:   55:	err_nonfatal(s);
+        1:   56:	exit(EXIT_FAILURE);
+        -:   57:}
+        -:   58:
+       11:   59:void logging(void) {
+        -:   60:#ifdef ISSERVER
+        -:   61:	openlog(MY_NAME, LOG_PID, LOG_DAEMON);
+        -:   62:#endif
+       11:   63:	setvbuf(stdout, NULL, _IONBF, 0);
+       11:   64:	setvbuf(stderr, NULL, _IONBF, 0);
+       11:   65:}
+        -:   66:
+        -:   67:#ifdef WORDS_BIGENDIAN
+        -:   68:inline u64 ntohll(u64 a) {
+        -:   69:	return a;
+        -:   70:}
+        -:   71:#else
+   106161:   72:inline u64 ntohll(u64 a) {
+   106161:   73:	u32 lo = a & 0xffffffff;
+   106161:   74:	u32 hi = a >> 32U;
+   106161:   75:	lo = ntohl(lo);
+   106161:   76:	hi = ntohl(hi);
+   106161:   77:	return ((u64) lo) << 32U | hi;
+        -:   78:}
+        -:   79:#endif
only in patch2:
unchanged:
--- nbd-3.8.orig/config.guess
+++ nbd-3.8/config.guess
@@ -1,8 +1,8 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
-#   Copyright 1992-2013 Free Software Foundation, Inc.
+#   Copyright 1992-2014 Free Software Foundation, Inc.
 
-timestamp='2013-06-10'
+timestamp='2014-03-23'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -50,7 +50,7 @@
 GNU config.guess ($timestamp)
 
 Originally written by Per Bothner.
-Copyright 1992-2013 Free Software Foundation, Inc.
+Copyright 1992-2014 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -149,7 +149,7 @@
 	LIBC=gnu
 	#endif
 	EOF
-	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
 	;;
 esac
 
@@ -826,7 +826,7 @@
     *:MINGW*:*)
 	echo ${UNAME_MACHINE}-pc-mingw32
 	exit ;;
-    i*:MSYS*:*)
+    *:MSYS*:*)
 	echo ${UNAME_MACHINE}-pc-msys
 	exit ;;
     i*:windows32*:*)
@@ -969,10 +969,10 @@
 	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
 	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
 	;;
-    or1k:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+    openrisc*:Linux:*:*)
+	echo or1k-unknown-linux-${LIBC}
 	exit ;;
-    or32:Linux:*:*)
+    or32:Linux:*:* | or1k*:Linux:*:*)
 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
 	exit ;;
     padre:Linux:*:*)
@@ -1260,16 +1260,26 @@
 	if test "$UNAME_PROCESSOR" = unknown ; then
 	    UNAME_PROCESSOR=powerpc
 	fi
-	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
-	    if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
-		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
-		grep IS_64BIT_ARCH >/dev/null
-	    then
-		case $UNAME_PROCESSOR in
-		    i386) UNAME_PROCESSOR=x86_64 ;;
-		    powerpc) UNAME_PROCESSOR=powerpc64 ;;
-		esac
+	if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
+	    if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+		if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+		    (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		    grep IS_64BIT_ARCH >/dev/null
+		then
+		    case $UNAME_PROCESSOR in
+			i386) UNAME_PROCESSOR=x86_64 ;;
+			powerpc) UNAME_PROCESSOR=powerpc64 ;;
+		    esac
+		fi
 	    fi
+	elif test "$UNAME_PROCESSOR" = i386 ; then
+	    # Avoid executing cc on OS X 10.9, as it ships with a stub
+	    # that puts up a graphical alert prompting to install
+	    # developer tools.  Any system running Mac OS X 10.7 or
+	    # later (Darwin 11 and later) is required to have a 64-bit
+	    # processor. This is not true of the ARM version of Darwin
+	    # that Apple uses in portable devices.
+	    UNAME_PROCESSOR=x86_64
 	fi
 	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
 	exit ;;
@@ -1361,154 +1371,6 @@
 	exit ;;
 esac
 
-eval $set_cc_for_build
-cat >$dummy.c <<EOF
-#ifdef _SEQUENT_
-# include <sys/types.h>
-# include <sys/utsname.h>
-#endif
-main ()
-{
-#if defined (sony)
-#if defined (MIPSEB)
-  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
-     I don't know....  */
-  printf ("mips-sony-bsd\n"); exit (0);
-#else
-#include <sys/param.h>
-  printf ("m68k-sony-newsos%s\n",
-#ifdef NEWSOS4
-	"4"
-#else
-	""
-#endif
-	); exit (0);
-#endif
-#endif
-
-#if defined (__arm) && defined (__acorn) && defined (__unix)
-  printf ("arm-acorn-riscix\n"); exit (0);
-#endif
-
-#if defined (hp300) && !defined (hpux)
-  printf ("m68k-hp-bsd\n"); exit (0);
-#endif
-
-#if defined (NeXT)
-#if !defined (__ARCHITECTURE__)
-#define __ARCHITECTURE__ "m68k"
-#endif
-  int version;
-  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
-  if (version < 4)
-    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
-  else
-    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
-  exit (0);
-#endif
-
-#if defined (MULTIMAX) || defined (n16)
-#if defined (UMAXV)
-  printf ("ns32k-encore-sysv\n"); exit (0);
-#else
-#if defined (CMU)
-  printf ("ns32k-encore-mach\n"); exit (0);
-#else
-  printf ("ns32k-encore-bsd\n"); exit (0);
-#endif
-#endif
-#endif
-
-#if defined (__386BSD__)
-  printf ("i386-pc-bsd\n"); exit (0);
-#endif
-
-#if defined (sequent)
-#if defined (i386)
-  printf ("i386-sequent-dynix\n"); exit (0);
-#endif
-#if defined (ns32000)
-  printf ("ns32k-sequent-dynix\n"); exit (0);
-#endif
-#endif
-
-#if defined (_SEQUENT_)
-    struct utsname un;
-
-    uname(&un);
-
-    if (strncmp(un.version, "V2", 2) == 0) {
-	printf ("i386-sequent-ptx2\n"); exit (0);
-    }
-    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
-	printf ("i386-sequent-ptx1\n"); exit (0);
-    }
-    printf ("i386-sequent-ptx\n"); exit (0);
-
-#endif
-
-#if defined (vax)
-# if !defined (ultrix)
-#  include <sys/param.h>
-#  if defined (BSD)
-#   if BSD == 43
-      printf ("vax-dec-bsd4.3\n"); exit (0);
-#   else
-#    if BSD == 199006
-      printf ("vax-dec-bsd4.3reno\n"); exit (0);
-#    else
-      printf ("vax-dec-bsd\n"); exit (0);
-#    endif
-#   endif
-#  else
-    printf ("vax-dec-bsd\n"); exit (0);
-#  endif
-# else
-    printf ("vax-dec-ultrix\n"); exit (0);
-# endif
-#endif
-
-#if defined (alliant) && defined (i860)
-  printf ("i860-alliant-bsd\n"); exit (0);
-#endif
-
-  exit (1);
-}
-EOF
-
-$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
-	{ echo "$SYSTEM_NAME"; exit; }
-
-# Apollos put the system type in the environment.
-
-test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
-
-# Convex versions that predate uname can use getsysinfo(1)
-
-if [ -x /usr/convex/getsysinfo ]
-then
-    case `getsysinfo -f cpu_type` in
-    c1*)
-	echo c1-convex-bsd
-	exit ;;
-    c2*)
-	if getsysinfo -f scalar_acc
-	then echo c32-convex-bsd
-	else echo c2-convex-bsd
-	fi
-	exit ;;
-    c34*)
-	echo c34-convex-bsd
-	exit ;;
-    c38*)
-	echo c38-convex-bsd
-	exit ;;
-    c4*)
-	echo c4-convex-bsd
-	exit ;;
-    esac
-fi
-
 cat >&2 <<EOF
 $0: unable to guess system type
 
only in patch2:
unchanged:
--- nbd-3.8.orig/config.sub
+++ nbd-3.8/config.sub
@@ -1,8 +1,8 @@
 #! /bin/sh
 # Configuration validation subroutine script.
-#   Copyright 1992-2013 Free Software Foundation, Inc.
+#   Copyright 1992-2014 Free Software Foundation, Inc.
 
-timestamp='2013-08-10'
+timestamp='2014-05-01'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -68,7 +68,7 @@
 version="\
 GNU config.sub ($timestamp)
 
-Copyright 1992-2013 Free Software Foundation, Inc.
+Copyright 1992-2014 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -265,6 +265,7 @@
 	| hexagon \
 	| i370 | i860 | i960 | ia64 \
 	| ip2k | iq2000 \
+	| k1om \
 	| le32 | le64 \
 	| lm32 \
 	| m32c | m32r | m32rle | m68000 | m68k | m88k \
@@ -282,8 +283,10 @@
 	| mips64vr5900 | mips64vr5900el \
 	| mipsisa32 | mipsisa32el \
 	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa32r6 | mipsisa32r6el \
 	| mipsisa64 | mipsisa64el \
 	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64r6 | mipsisa64r6el \
 	| mipsisa64sb1 | mipsisa64sb1el \
 	| mipsisa64sr71k | mipsisa64sr71kel \
 	| mipsr5900 | mipsr5900el \
@@ -295,8 +298,7 @@
 	| nds32 | nds32le | nds32be \
 	| nios | nios2 | nios2eb | nios2el \
 	| ns16k | ns32k \
-	| open8 \
-	| or1k | or32 \
+	| open8 | or1k | or1knd | or32 \
 	| pdp10 | pdp11 | pj | pjl \
 	| powerpc | powerpc64 | powerpc64le | powerpcle \
 	| pyramid \
@@ -324,7 +326,7 @@
 	c6x)
 		basic_machine=tic6x-unknown
 		;;
-	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
+	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
 		basic_machine=$basic_machine-unknown
 		os=-none
 		;;
@@ -381,6 +383,7 @@
 	| hexagon-* \
 	| i*86-* | i860-* | i960-* | ia64-* \
 	| ip2k-* | iq2000-* \
+	| k1om-* \
 	| le32-* | le64-* \
 	| lm32-* \
 	| m32c-* | m32r-* | m32rle-* \
@@ -400,8 +403,10 @@
 	| mips64vr5900-* | mips64vr5900el-* \
 	| mipsisa32-* | mipsisa32el-* \
 	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa32r6-* | mipsisa32r6el-* \
 	| mipsisa64-* | mipsisa64el-* \
 	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64r6-* | mipsisa64r6el-* \
 	| mipsisa64sb1-* | mipsisa64sb1el-* \
 	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
 	| mipsr5900-* | mipsr5900el-* \
@@ -413,6 +418,7 @@
 	| nios-* | nios2-* | nios2eb-* | nios2el-* \
 	| none-* | np1-* | ns16k-* | ns32k-* \
 	| open8-* \
+	| or1k*-* \
 	| orion-* \
 	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
 	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
@@ -1374,7 +1380,7 @@
 	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
 	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
 	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
-	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
 	# Remember, each alternative MUST END IN *, to match a version number.
 		;;
 	-qnx*)
@@ -1592,9 +1598,6 @@
 	mips*-*)
 		os=-elf
 		;;
-	or1k-*)
-		os=-elf
-		;;
 	or32-*)
 		os=-coff
 		;;
only in patch2:
unchanged:
--- nbd-3.8.orig/configure
+++ nbd-3.8/configure
@@ -13405,13 +13405,10 @@
 main ()
 {
   unsigned int major, minor, micro;
-  char *tmp_version;
 
   fclose (fopen ("conf.glibtest", "w"));
 
-  /* HP/UX 9 (%@#!) writes to sscanf strings */
-  tmp_version = g_strdup("$min_glib_version");
-  if (sscanf(tmp_version, "%u.%u.%u", &major, &minor, &micro) != 3) {
+  if (sscanf("$min_glib_version", "%u.%u.%u", &major, &minor, &micro) != 3) {
      printf("%s, bad version string\n", "$min_glib_version");
      exit(1);
    }
only in patch2:
unchanged:
--- nbd-3.8.orig/gznbd/Makefile.in
+++ nbd-3.8/gznbd/Makefile.in
@@ -0,0 +1,641 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@GZNBD_TRUE@bin_PROGRAMS = gznbd$(EXEEXT)
+subdir = gznbd
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+	$(top_srcdir)/depcomp
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+PROGRAMS = $(bin_PROGRAMS)
+am__gznbd_SOURCES_DIST = gznbd.c
+@GZNBD_TRUE@am_gznbd_OBJECTS = gznbd-gznbd.$(OBJEXT)
+gznbd_OBJECTS = $(am_gznbd_OBJECTS)
+@GZNBD_TRUE@gznbd_DEPENDENCIES = ../libcliserv.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+gznbd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(gznbd_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(gznbd_SOURCES)
+DIST_SOURCES = $(am__gznbd_SOURCES_DIST)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NBD_CLIENT_NAME = @NBD_CLIENT_NAME@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nbd_server_CPPFLAGS = @nbd_server_CPPFLAGS@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@GZNBD_TRUE@gznbd_SOURCES = gznbd.c
+@GZNBD_TRUE@gznbd_CFLAGS = -DTRACE -Wall
+@GZNBD_TRUE@gznbd_LDADD = -lz ../libcliserv.la
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gznbd/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign gznbd/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-binPROGRAMS: $(bin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+	fi; \
+	for p in $$list; do echo "$$p $$p"; done | \
+	sed 's/$(EXEEXT)$$//' | \
+	while read p p1; do if test -f $$p \
+	 || test -f $$p1 \
+	  ; then echo "$$p"; echo "$$p"; else :; fi; \
+	done | \
+	sed -e 'p;s,.*/,,;n;h' \
+	    -e 's|.*|.|' \
+	    -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+	sed 'N;N;N;s,\n, ,g' | \
+	$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+	  { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+	    if ($$2 == $$4) files[d] = files[d] " " $$1; \
+	    else { print "f", $$3 "/" $$4, $$1; } } \
+	  END { for (d in files) print "f", d, files[d] }' | \
+	while read type dir files; do \
+	    if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+	    test -z "$$files" || { \
+	    echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+	    $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+	    } \
+	; done
+
+uninstall-binPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+	files=`for p in $$list; do echo "$$p"; done | \
+	  sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+	      -e 's/$$/$(EXEEXT)/' \
+	`; \
+	test -n "$$list" || exit 0; \
+	echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+	cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+	@list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+gznbd$(EXEEXT): $(gznbd_OBJECTS) $(gznbd_DEPENDENCIES) $(EXTRA_gznbd_DEPENDENCIES) 
+	@rm -f gznbd$(EXEEXT)
+	$(AM_V_CCLD)$(gznbd_LINK) $(gznbd_OBJECTS) $(gznbd_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gznbd-gznbd.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+gznbd-gznbd.o: gznbd.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gznbd_CFLAGS) $(CFLAGS) -MT gznbd-gznbd.o -MD -MP -MF $(DEPDIR)/gznbd-gznbd.Tpo -c -o gznbd-gznbd.o `test -f 'gznbd.c' || echo '$(srcdir)/'`gznbd.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/gznbd-gznbd.Tpo $(DEPDIR)/gznbd-gznbd.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='gznbd.c' object='gznbd-gznbd.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gznbd_CFLAGS) $(CFLAGS) -c -o gznbd-gznbd.o `test -f 'gznbd.c' || echo '$(srcdir)/'`gznbd.c
+
+gznbd-gznbd.obj: gznbd.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gznbd_CFLAGS) $(CFLAGS) -MT gznbd-gznbd.obj -MD -MP -MF $(DEPDIR)/gznbd-gznbd.Tpo -c -o gznbd-gznbd.obj `if test -f 'gznbd.c'; then $(CYGPATH_W) 'gznbd.c'; else $(CYGPATH_W) '$(srcdir)/gznbd.c'; fi`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/gznbd-gznbd.Tpo $(DEPDIR)/gznbd-gznbd.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='gznbd.c' object='gznbd-gznbd.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gznbd_CFLAGS) $(CFLAGS) -c -o gznbd-gznbd.obj `if test -f 'gznbd.c'; then $(CYGPATH_W) 'gznbd.c'; else $(CYGPATH_W) '$(srcdir)/gznbd.c'; fi`
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+	for dir in "$(DESTDIR)$(bindir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \
+	clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \
+	ctags ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-binPROGRAMS \
+	install-data install-data-am install-dvi install-dvi-am \
+	install-exec install-exec-am install-html install-html-am \
+	install-info install-info-am install-man install-pdf \
+	install-pdf-am install-ps install-ps-am install-strip \
+	installcheck installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am uninstall-binPROGRAMS
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
only in patch2:
unchanged:
--- nbd-3.8.orig/libcliserv.la
+++ nbd-3.8/libcliserv.la
@@ -0,0 +1,41 @@
+# libcliserv.la - a libtool library file
+# Generated by libtool (GNU libtool) 2.4.2 Debian-2.4.2-1.7
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname=''
+
+# Names of this library.
+library_names=''
+
+# The name of the static archive.
+old_library='libcliserv.a'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags=''
+
+# Libraries that this one depends upon.
+dependency_libs=''
+
+# Names of additional weak libraries provided by this library
+weak_library_names=''
+
+# Version information for libcliserv.
+current=
+age=
+revision=
+
+# Is this an already installed library?
+installed=no
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=no
+
+# Files to dlopen/dlpreopen
+dlopen=''
+dlpreopen=''
+
+# Directory that this library needs to be installed in:
+libdir=''
only in patch2:
unchanged:
--- nbd-3.8.orig/nbd-client.c.gcov
+++ nbd-3.8/nbd-client.c.gcov
@@ -0,0 +1,679 @@
+        -:    0:Source:nbd-client.c
+        -:    0:Programs:4
+        -:    1:/*
+        -:    2: * Open connection for network block device
+        -:    3: *
+        -:    4: * Copyright 1997,1998 Pavel Machek, distribute under GPL
+        -:    5: *  <pavel@atrey.karlin.mff.cuni.cz>
+        -:    6: * Copyright (c) 2002 - 2011 Wouter Verhelst <w@uter.be>
+        -:    7: *
+        -:    8: * Version 1.0 - 64bit issues should be fixed, now
+        -:    9: * Version 1.1 - added bs (blocksize) option (Alexey Guzeev, aga@permonline.ru)
+        -:   10: * Version 1.2 - I added new option '-d' to send the disconnect request
+        -:   11: * Version 2.0 - Version synchronised with server
+        -:   12: * Version 2.1 - Check for disconnection before INIT_PASSWD is received
+        -:   13: * 	to make errormsg a bit more helpful in case the server can't
+        -:   14: * 	open the exported file.
+        -:   15: * 16/03/2010 - Add IPv6 support.
+        -:   16: * 	Kitt Tientanopajai <kitt@kitty.in.th>
+        -:   17: *	Neutron Soutmun <neo.neutron@gmail.com>
+        -:   18: *	Suriya Soutmun <darksolar@gmail.com>
+        -:   19: */
+        -:   20:
+        -:   21:#include "config.h"
+        -:   22:#include "lfs.h"
+        -:   23:
+        -:   24:#include <sys/ioctl.h>
+        -:   25:#include <sys/socket.h>
+        -:   26:#include <sys/types.h>
+        -:   27:#include <unistd.h>
+        -:   28:#include <netinet/tcp.h>
+        -:   29:#include <netinet/in.h>
+        -:   30:#include <netdb.h>
+        -:   31:#include "netdb-compat.h"
+        -:   32:#include <stdio.h>
+        -:   33:#include <fcntl.h>
+        -:   34:#include <syslog.h>
+        -:   35:#include <stdlib.h>
+        -:   36:#include <sys/mount.h>
+        -:   37:#include <sys/mman.h>
+        -:   38:#include <signal.h>
+        -:   39:#include <errno.h>
+        -:   40:#include <getopt.h>
+        -:   41:#include <stdarg.h>
+        -:   42:
+        -:   43:#include <linux/ioctl.h>
+        -:   44:#define MY_NAME "nbd_client"
+        -:   45:#include "cliserv.h"
+        -:   46:
+        -:   47:#ifdef WITH_SDP
+        -:   48:#include <sdp_inet.h>
+        -:   49:#endif
+        -:   50:
+        -:   51:#define NBDC_DO_LIST 1
+        -:   52:
+    #####:   53:int check_conn(char* devname, int do_print) {
+        -:   54:	char buf[256];
+        -:   55:	char* p;
+        -:   56:	int fd;
+        -:   57:	int len;
+        -:   58:
+    #####:   59:	if( (p=strrchr(devname, '/')) ) {
+    #####:   60:		devname=p+1;
+        -:   61:	}
+    #####:   62:	if((p=strchr(devname, 'p'))) {
+        -:   63:		/* We can't do checks on partitions. */
+    #####:   64:		*p='\0';
+        -:   65:	}
+    #####:   66:	snprintf(buf, 256, "/sys/block/%s/pid", devname);
+    #####:   67:	if((fd=open(buf, O_RDONLY))<0) {
+    #####:   68:		if(errno==ENOENT) {
+    #####:   69:			return 1;
+        -:   70:		} else {
+    #####:   71:			return 2;
+        -:   72:		}
+        -:   73:	}
+    #####:   74:	len=read(fd, buf, 256);
+    #####:   75:	if(len < 0) {
+    #####:   76:		perror("could not read from server");
+        -:   77:	}
+    #####:   78:	buf[len]='\0';
+    #####:   79:	if(do_print) printf("%s\n", buf);
+    #####:   80:	return 0;
+        -:   81:}
+        -:   82:
+        1:   83:int opennet(char *name, char* portstr, int sdp) {
+        -:   84:	int sock;
+        -:   85:	struct addrinfo hints;
+        1:   86:	struct addrinfo *ai = NULL;
+        1:   87:	struct addrinfo *rp = NULL;
+        -:   88:	int e;
+        -:   89:
+        1:   90:	memset(&hints,'\0',sizeof(hints));
+        1:   91:	hints.ai_family = AF_UNSPEC;
+        1:   92:	hints.ai_socktype = SOCK_STREAM;
+        1:   93:	hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
+        1:   94:	hints.ai_protocol = IPPROTO_TCP;
+        -:   95:
+        1:   96:	e = getaddrinfo(name, portstr, &hints, &ai);
+        -:   97:
+        1:   98:	if(e != 0) {
+    #####:   99:		fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
+    #####:  100:		freeaddrinfo(ai);
+    #####:  101:		return -1;
+        -:  102:	}
+        -:  103:
+        1:  104:	if(sdp) {
+        -:  105:#ifdef WITH_SDP
+        -:  106:		if (ai->ai_family == AF_INET)
+        -:  107:			ai->ai_family = AF_INET_SDP;
+        -:  108:		else (ai->ai_family == AF_INET6)
+        -:  109:			ai->ai_family = AF_INET6_SDP;
+        -:  110:#else
+    #####:  111:		err("Can't do SDP: I was not compiled with SDP support!");
+        -:  112:#endif
+        -:  113:	}
+        -:  114:
+        1:  115:	for(rp = ai; rp != NULL; rp = rp->ai_next) {
+        1:  116:		sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+        -:  117:
+        1:  118:		if(sock == -1)
+    #####:  119:			continue;	/* error */
+        -:  120:
+        1:  121:		if(connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
+        1:  122:			break;		/* success */
+        -:  123:			
+    #####:  124:		close(sock);
+        -:  125:	}
+        -:  126:
+        1:  127:	if (rp == NULL) {
+    #####:  128:		err_nonfatal("Socket failed: %m");
+    #####:  129:		sock = -1;
+    #####:  130:		goto err;
+        -:  131:	}
+        -:  132:
+        1:  133:	setmysockopt(sock);
+        -:  134:err:
+        1:  135:	freeaddrinfo(ai);
+        1:  136:	return sock;
+        -:  137:}
+        -:  138:
+        1:  139:void ask_list(int sock) {
+        -:  140:	uint32_t opt;
+        -:  141:	uint32_t opt_server;
+        -:  142:	uint32_t len;
+        -:  143:	uint32_t reptype;
+        -:  144:	uint64_t magic;
+        1:  145:	const int BUF_SIZE = 1024;
+        1:  146:	char buf[BUF_SIZE];
+        -:  147:
+        1:  148:	magic = ntohll(opts_magic);
+        1:  149:	if (write(sock, &magic, sizeof(magic)) < 0)
+    #####:  150:		err("Failed/2.2: %m");
+        -:  151:
+        -:  152:	/* Ask for the list */
+        1:  153:	opt = htonl(NBD_OPT_LIST);
+        1:  154:	if(write(sock, &opt, sizeof(opt)) < 0) {
+    #####:  155:		err("writing list option failed: %m");
+        -:  156:	}
+        -:  157:	/* Send the length (zero) */
+        1:  158:	len = htonl(0);
+        1:  159:	if(write(sock, &len, sizeof(len)) < 0) {
+    #####:  160:		err("writing length failed: %m");
+        -:  161:	}
+        -:  162:	/* newline, move away from the "Negotiation:" line */
+        1:  163:	printf("\n");
+        -:  164:	do {
+        2:  165:		memset(buf, 0, 1024);
+        2:  166:		if(read(sock, &magic, sizeof(magic)) < 0) {
+    #####:  167:			err("Reading magic from server: %m");
+        -:  168:		}
+        2:  169:		if(read(sock, &opt_server, sizeof(opt_server)) < 0) {
+    #####:  170:			err("Reading option: %m");
+        -:  171:		}
+        2:  172:		if(read(sock, &reptype, sizeof(reptype)) <0) {
+    #####:  173:			err("Reading reply from server: %m");
+        -:  174:		}
+        2:  175:		if(read(sock, &len, sizeof(len)) < 0) {
+    #####:  176:			err("Reading length from server: %m");
+        -:  177:		}
+        2:  178:		magic=ntohll(magic);
+        2:  179:		len=ntohl(len);
+        2:  180:		reptype=ntohl(reptype);
+        2:  181:		if(magic != rep_magic) {
+    #####:  182:			err("Not enough magic from server");
+        -:  183:		}
+        2:  184:		if(reptype & NBD_REP_FLAG_ERROR) {
+    #####:  185:			switch(reptype) {
+        -:  186:				case NBD_REP_ERR_POLICY:
+    #####:  187:					fprintf(stderr, "\nE: listing not allowed by server.\n");
+    #####:  188:					break;
+        -:  189:				default:
+    #####:  190:					fprintf(stderr, "\nE: unexpected error from server.\n");
+    #####:  191:					break;
+        -:  192:			}
+    #####:  193:			if(len > 0 && len < BUF_SIZE) {
+    #####:  194:				if(len=read(sock, buf, len) < 0) {
+    #####:  195:					fprintf(stderr, "\nE: could not read error message from server\n");
+        -:  196:				}
+    #####:  197:				buf[len] = '\0';
+    #####:  198:				fprintf(stderr, "Server said: %s\n", buf);
+        -:  199:			}
+    #####:  200:			exit(EXIT_FAILURE);
+        -:  201:		} else {
+        2:  202:			if(len) {
+        1:  203:				if(reptype != NBD_REP_SERVER) {
+    #####:  204:					err("Server sent us a reply we don't understand!");
+        -:  205:				}
+        1:  206:				if(read(sock, &len, sizeof(len)) < 0) {
+    #####:  207:					fprintf(stderr, "\nE: could not read export name length from server\n");
+    #####:  208:					exit(EXIT_FAILURE);
+        -:  209:				}
+        1:  210:				len=ntohl(len);
+        1:  211:				if (len >= BUF_SIZE) {
+    #####:  212:					fprintf(stderr, "\nE: export name on server too long\n");
+    #####:  213:					exit(EXIT_FAILURE);
+        -:  214:				}
+        1:  215:				if(read(sock, buf, len) < 0) {
+    #####:  216:					fprintf(stderr, "\nE: could not read export name from server\n");
+    #####:  217:					exit(EXIT_FAILURE);
+        -:  218:				}
+        1:  219:				buf[len] = 0;
+        1:  220:				printf("%s\n", buf);
+        -:  221:			}
+        -:  222:		}
+        2:  223:	} while(reptype != NBD_REP_ACK);
+        1:  224:	opt=htonl(NBD_OPT_ABORT);
+        1:  225:	len=htonl(0);
+        1:  226:	magic=htonll(opts_magic);
+        1:  227:	if (write(sock, &magic, sizeof(magic)) < 0)
+    #####:  228:		err("Failed/2.2: %m");
+        1:  229:	if (write(sock, &opt, sizeof(opt)) < 0)
+    #####:  230:		err("Failed writing abort");
+        1:  231:	if (write(sock, &len, sizeof(len)) < 0)
+    #####:  232:		err("Failed writing length");
+        1:  233:}
+        -:  234:
+        1:  235:void negotiate(int sock, u64 *rsize64, u32 *flags, char* name, uint32_t needed_flags, uint32_t client_flags, uint32_t do_opts) {
+        -:  236:	u64 magic, size64;
+        -:  237:	uint16_t tmp;
+        1:  238:	char buf[256] = "\0\0\0\0\0\0\0\0\0";
+        -:  239:
+        1:  240:	printf("Negotiation: ");
+        1:  241:	if (read(sock, buf, 8) < 0)
+    #####:  242:		err("Failed/1: %m");
+        1:  243:	if (strlen(buf)==0)
+    #####:  244:		err("Server closed connection");
+        1:  245:	if (strcmp(buf, INIT_PASSWD))
+    #####:  246:		err("INIT_PASSWD bad");
+        1:  247:	printf(".");
+        1:  248:	if (read(sock, &magic, sizeof(magic)) < 0)
+    #####:  249:		err("Failed/2: %m");
+        1:  250:	magic = ntohll(magic);
+        1:  251:	if(name) {
+        -:  252:		uint32_t opt;
+        -:  253:		uint32_t namesize;
+        -:  254:
+        1:  255:		if (magic != opts_magic) {
+    #####:  256:			if(magic == cliserv_magic) {
+    #####:  257:				err("It looks like you're trying to connect to an oldstyle server with a named export. This won't work.");
+        -:  258:			}
+        -:  259:		}
+        1:  260:		printf(".");
+        1:  261:		if(read(sock, &tmp, sizeof(uint16_t)) < 0) {
+    #####:  262:			err("Failed reading flags: %m");
+        -:  263:		}
+        1:  264:		*flags = ((u32)ntohs(tmp));
+        1:  265:		if((needed_flags & *flags) != needed_flags) {
+        -:  266:			/* There's currently really only one reason why this
+        -:  267:			 * check could possibly fail, but we may need to change
+        -:  268:			 * this error message in the future... */
+    #####:  269:			fprintf(stderr, "\nE: Server does not support listing exports\n");
+    #####:  270:			exit(EXIT_FAILURE);
+        -:  271:		}
+        -:  272:
+        1:  273:		client_flags = htonl(client_flags);
+        1:  274:		if (write(sock, &client_flags, sizeof(client_flags)) < 0)
+    #####:  275:			err("Failed/2.1: %m");
+        -:  276:
+        1:  277:		if(do_opts & NBDC_DO_LIST) {
+        1:  278:			ask_list(sock);
+        1:  279:			exit(EXIT_SUCCESS);
+        -:  280:		}
+        -:  281:
+        -:  282:		/* Write the export name that we're after */
+    #####:  283:		magic = htonll(opts_magic);
+    #####:  284:		if (write(sock, &magic, sizeof(magic)) < 0)
+    #####:  285:			err("Failed/2.2: %m");
+        -:  286:
+    #####:  287:		opt = ntohl(NBD_OPT_EXPORT_NAME);
+    #####:  288:		if (write(sock, &opt, sizeof(opt)) < 0)
+    #####:  289:			err("Failed/2.3: %m");
+    #####:  290:		namesize = (u32)strlen(name);
+    #####:  291:		namesize = ntohl(namesize);
+    #####:  292:		if (write(sock, &namesize, sizeof(namesize)) < 0)
+    #####:  293:			err("Failed/2.4: %m");
+    #####:  294:		if (write(sock, name, strlen(name)) < 0)
+    #####:  295:			err("Failed/2.4: %m");
+        -:  296:	} else {
+    #####:  297:		if (magic != cliserv_magic) {
+    #####:  298:			if(magic != opts_magic)
+    #####:  299:				err("Not enough cliserv_magic");
+        -:  300:			else
+    #####:  301:				err("It looks like you're trying to connect to a newstyle server with the oldstyle protocol. Try the -N option.");
+        -:  302:		}
+    #####:  303:		printf(".");
+        -:  304:	}
+        -:  305:
+    #####:  306:	if (read(sock, &size64, sizeof(size64)) <= 0) {
+    #####:  307:		if (!errno)
+    #####:  308:			err("Server closed connection");
+    #####:  309:		err("Failed/3: %m\n");
+        -:  310:	}
+    #####:  311:	size64 = ntohll(size64);
+        -:  312:
+        -:  313:	if ((size64>>12) > (uint64_t)~0UL) {
+        -:  314:		printf("size = %luMB", (unsigned long)(size64>>20));
+        -:  315:		err("Exported device is too big for me. Get 64-bit machine :-(\n");
+        -:  316:	} else
+    #####:  317:		printf("size = %luMB", (unsigned long)(size64>>20));
+        -:  318:
+    #####:  319:	if(!name) {
+    #####:  320:		if (read(sock, flags, sizeof(*flags)) < 0)
+    #####:  321:			err("Failed/4: %m\n");
+    #####:  322:		*flags = ntohl(*flags);
+        -:  323:	} else {
+    #####:  324:		if(read(sock, &tmp, sizeof(tmp)) < 0)
+    #####:  325:			err("Failed/4: %m\n");
+    #####:  326:		*flags |= (uint32_t)ntohs(tmp);
+        -:  327:	}
+        -:  328:
+    #####:  329:	if (read(sock, &buf, 124) < 0)
+    #####:  330:		err("Failed/5: %m\n");
+    #####:  331:	printf("\n");
+        -:  332:
+    #####:  333:	*rsize64 = size64;
+    #####:  334:}
+        -:  335:
+    #####:  336:void setsizes(int nbd, u64 size64, int blocksize, u32 flags) {
+        -:  337:	unsigned long size;
+    #####:  338:	int read_only = (flags & NBD_FLAG_READ_ONLY) ? 1 : 0;
+        -:  339:
+        -:  340:	if (size64>>12 > (uint64_t)~0UL)
+        -:  341:		err("Device too large.\n");
+        -:  342:	else {
+    #####:  343:		if (ioctl(nbd, NBD_SET_BLKSIZE, 4096UL) < 0)
+    #####:  344:			err("Ioctl/1.1a failed: %m\n");
+    #####:  345:		size = (unsigned long)(size64>>12);
+    #####:  346:		if (ioctl(nbd, NBD_SET_SIZE_BLOCKS, size) < 0)
+    #####:  347:			err("Ioctl/1.1b failed: %m\n");
+    #####:  348:		if (ioctl(nbd, NBD_SET_BLKSIZE, (unsigned long)blocksize) < 0)
+    #####:  349:			err("Ioctl/1.1c failed: %m\n");
+    #####:  350:		fprintf(stderr, "bs=%d, sz=%llu bytes\n", blocksize, 4096ULL*size);
+        -:  351:	}
+        -:  352:
+    #####:  353:	ioctl(nbd, NBD_CLEAR_SOCK);
+        -:  354:
+        -:  355:	/* ignore error as kernel may not support */
+    #####:  356:	ioctl(nbd, NBD_SET_FLAGS, (unsigned long) flags);
+        -:  357:
+    #####:  358:	if (ioctl(nbd, BLKROSET, (unsigned long) &read_only) < 0)
+    #####:  359:		err("Unable to set read-only attribute for device");
+    #####:  360:}
+        -:  361:
+    #####:  362:void set_timeout(int nbd, int timeout) {
+    #####:  363:	if (timeout) {
+    #####:  364:		if (ioctl(nbd, NBD_SET_TIMEOUT, (unsigned long)timeout) < 0)
+    #####:  365:			err("Ioctl NBD_SET_TIMEOUT failed: %m\n");
+    #####:  366:		fprintf(stderr, "timeout=%d\n", timeout);
+        -:  367:	}
+    #####:  368:}
+        -:  369:
+    #####:  370:void finish_sock(int sock, int nbd, int swap) {
+    #####:  371:	if (ioctl(nbd, NBD_SET_SOCK, sock) < 0)
+    #####:  372:		err("Ioctl NBD_SET_SOCK failed: %m\n");
+        -:  373:
+    #####:  374:	if (swap)
+    #####:  375:		mlockall(MCL_CURRENT | MCL_FUTURE);
+    #####:  376:}
+        -:  377:
+        -:  378:static int
+    #####:  379:oom_adjust(const char *file, const char *value)
+        -:  380:{
+        -:  381:	int fd, rc;
+        -:  382:	size_t len;
+        -:  383:
+    #####:  384:	fd = open(file, O_WRONLY);
+    #####:  385:	if (fd < 0)
+    #####:  386:		return -1;
+    #####:  387:	len = strlen(value);
+    #####:  388:	rc = write(fd, value, len) != (ssize_t) len;
+    #####:  389:	close(fd);
+    #####:  390:	return rc ? -1 : 0;
+        -:  391:}
+        -:  392:
+    #####:  393:void usage(char* errmsg, ...) {
+    #####:  394:	if(errmsg) {
+        -:  395:		char tmp[256];
+        -:  396:		va_list ap;
+    #####:  397:		va_start(ap, errmsg);
+    #####:  398:		snprintf(tmp, 256, "ERROR: %s\n\n", errmsg);
+    #####:  399:		vfprintf(stderr, tmp, ap);
+    #####:  400:		va_end(ap);
+        -:  401:	} else {
+    #####:  402:		fprintf(stderr, "nbd-client version %s\n", PACKAGE_VERSION);
+        -:  403:	}
+    #####:  404:	fprintf(stderr, "Usage: nbd-client host port nbd_device [-block-size|-b block size] [-timeout|-t timeout] [-swap|-s] [-sdp|-S] [-persist|-p] [-nofork|-n] [-systemd-mark|-m]\n");
+    #####:  405:	fprintf(stderr, "Or   : nbd-client -name|-N name host [port] nbd_device [-block-size|-b block size] [-timeout|-t timeout] [-swap|-s] [-sdp|-S] [-persist|-p] [-nofork|-n]\n");
+    #####:  406:	fprintf(stderr, "Or   : nbd-client -d nbd_device\n");
+    #####:  407:	fprintf(stderr, "Or   : nbd-client -c nbd_device\n");
+    #####:  408:	fprintf(stderr, "Or   : nbd-client -h|--help\n");
+    #####:  409:	fprintf(stderr, "Or   : nbd-client -l|--list host\n");
+    #####:  410:	fprintf(stderr, "Default value for blocksize is 1024 (recommended for ethernet)\n");
+    #####:  411:	fprintf(stderr, "Allowed values for blocksize are 512,1024,2048,4096\n"); /* will be checked in kernel :) */
+    #####:  412:	fprintf(stderr, "Note, that kernel 2.4.2 and older ones do not work correctly with\n");
+    #####:  413:	fprintf(stderr, "blocksizes other than 1024 without patches\n");
+    #####:  414:	fprintf(stderr, "Default value for port with -N is 10809. Note that port must always be numeric\n");
+    #####:  415:}
+        -:  416:
+    #####:  417:void disconnect(char* device) {
+    #####:  418:	int nbd = open(device, O_RDWR);
+        -:  419:
+    #####:  420:	if (nbd < 0)
+    #####:  421:		err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
+    #####:  422:	printf("disconnect, ");
+    #####:  423:	if (ioctl(nbd, NBD_DISCONNECT)<0)
+    #####:  424:		err("Ioctl failed: %m\n");
+    #####:  425:	printf("sock, ");
+    #####:  426:	if (ioctl(nbd, NBD_CLEAR_SOCK)<0)
+    #####:  427:		err("Ioctl failed: %m\n");
+    #####:  428:	printf("done\n");
+    #####:  429:}
+        -:  430:
+        1:  431:int main(int argc, char *argv[]) {
+        1:  432:	char* port=NULL;
+        -:  433:	int sock, nbd;
+        1:  434:	int blocksize=1024;
+        1:  435:	char *hostname=NULL;
+        1:  436:	char *nbddev=NULL;
+        1:  437:	int swap=0;
+        1:  438:	int cont=0;
+        1:  439:	int timeout=0;
+        1:  440:	int sdp=0;
+        1:  441:	int G_GNUC_UNUSED nofork=0; // if -dNOFORK
+        -:  442:	u64 size64;
+        -:  443:	u32 flags;
+        -:  444:	int c;
+        1:  445:	int nonspecial=0;
+        1:  446:	char* name=NULL;
+        1:  447:	uint32_t needed_flags=0;
+        1:  448:	uint32_t cflags=0;
+        1:  449:	uint32_t opts=0;
+        -:  450:	sigset_t block, old;
+        -:  451:	struct sigaction sa;
+        1:  452:	struct option long_options[] = {
+        -:  453:		{ "block-size", required_argument, NULL, 'b' },
+        -:  454:		{ "check", required_argument, NULL, 'c' },
+        -:  455:		{ "disconnect", required_argument, NULL, 'd' },
+        -:  456:		{ "help", no_argument, NULL, 'h' },
+        -:  457:		{ "list", no_argument, NULL, 'l' },
+        -:  458:		{ "name", required_argument, NULL, 'N' },
+        -:  459:		{ "nofork", no_argument, NULL, 'n' },
+        -:  460:		{ "persist", no_argument, NULL, 'p' },
+        -:  461:		{ "sdp", no_argument, NULL, 'S' },
+        -:  462:		{ "swap", no_argument, NULL, 's' },
+        -:  463:		{ "systemd-mark", no_argument, NULL, 'm' },
+        -:  464:		{ "timeout", required_argument, NULL, 't' },
+        -:  465:		{ 0, 0, 0, 0 }, 
+        -:  466:	};
+        -:  467:
+        1:  468:	logging();
+        -:  469:
+        1:  470:	while((c=getopt_long_only(argc, argv, "-b:c:d:hlnN:pSst:", long_options, NULL))>=0) {
+        2:  471:		switch(c) {
+        -:  472:		case 1:
+        -:  473:			// non-option argument
+        1:  474:			if(strchr(optarg, '=')) {
+        -:  475:				// old-style 'bs=' or 'timeout='
+        -:  476:				// argument
+    #####:  477:				fprintf(stderr, "WARNING: old-style command-line argument encountered. This is deprecated.\n");
+    #####:  478:				if(!strncmp(optarg, "bs=", 3)) {
+    #####:  479:					optarg+=3;
+    #####:  480:					goto blocksize;
+        -:  481:				}
+    #####:  482:				if(!strncmp(optarg, "timeout=", 8)) {
+    #####:  483:					optarg+=8;
+    #####:  484:					goto timeout;
+        -:  485:				}
+    #####:  486:				usage("unknown option %s encountered", optarg);
+    #####:  487:				exit(EXIT_FAILURE);
+        -:  488:			}
+        1:  489:			switch(nonspecial++) {
+        -:  490:				case 0:
+        -:  491:					// host
+        1:  492:					hostname=optarg;
+        1:  493:					break;
+        -:  494:				case 1:
+        -:  495:					// port
+    #####:  496:					if(!strtol(optarg, NULL, 0)) {
+        -:  497:						// not parseable as a number, assume it's the device and we have a name
+    #####:  498:						nbddev = optarg;
+    #####:  499:						nonspecial++;
+        -:  500:					} else {
+    #####:  501:						port = optarg;
+        -:  502:					}
+    #####:  503:					break;
+        -:  504:				case 2:
+        -:  505:					// device
+    #####:  506:					nbddev = optarg;
+    #####:  507:					break;
+        -:  508:				default:
+    #####:  509:					usage("too many non-option arguments specified");
+    #####:  510:					exit(EXIT_FAILURE);
+        -:  511:			}
+        1:  512:			break;
+        -:  513:		case 'b':
+        -:  514:		      blocksize:
+    #####:  515:			blocksize=(int)strtol(optarg, NULL, 0);
+    #####:  516:			break;
+        -:  517:		case 'c':
+    #####:  518:			return check_conn(optarg, 1);
+        -:  519:		case 'd':
+    #####:  520:			disconnect(optarg);
+    #####:  521:			exit(EXIT_SUCCESS);
+        -:  522:		case 'h':
+    #####:  523:			usage(NULL);
+    #####:  524:			exit(EXIT_SUCCESS);
+        -:  525:		case 'l':
+        1:  526:			needed_flags |= NBD_FLAG_FIXED_NEWSTYLE;
+        1:  527:			cflags |= NBD_FLAG_C_FIXED_NEWSTYLE;
+        1:  528:			opts |= NBDC_DO_LIST;
+        1:  529:			name="";
+        1:  530:			nbddev="";
+        1:  531:			port = NBD_DEFAULT_PORT;
+        1:  532:			break;
+        -:  533:		case 'm':
+    #####:  534:			argv[0][0] = '@';
+    #####:  535:			break;
+        -:  536:		case 'n':
+    #####:  537:			nofork=1;
+    #####:  538:			break;
+        -:  539:		case 'N':
+    #####:  540:			name=optarg;
+    #####:  541:			if(!port) {
+    #####:  542:				port = NBD_DEFAULT_PORT;
+        -:  543:			}
+    #####:  544:			break;
+        -:  545:		case 'p':
+    #####:  546:			cont=1;
+    #####:  547:			break;
+        -:  548:		case 's':
+    #####:  549:			swap=1;
+    #####:  550:			break;
+        -:  551:		case 'S':
+    #####:  552:			sdp=1;
+    #####:  553:			break;
+        -:  554:		case 't':
+        -:  555:		      timeout:
+    #####:  556:			timeout=strtol(optarg, NULL, 0);
+    #####:  557:			break;
+        -:  558:		default:
+    #####:  559:			fprintf(stderr, "E: option eaten by 42 mice\n");
+    #####:  560:			exit(EXIT_FAILURE);
+        -:  561:		}
+        -:  562:	}
+        -:  563:
+        1:  564:	if((!port && !name) || !hostname || !nbddev) {
+    #####:  565:		usage("not enough information specified");
+    #####:  566:		exit(EXIT_FAILURE);
+        -:  567:	}
+        -:  568:
+        1:  569:	sock = opennet(hostname, port, sdp);
+        1:  570:	if (sock < 0)
+    #####:  571:		exit(EXIT_FAILURE);
+        -:  572:
+        1:  573:	negotiate(sock, &size64, &flags, name, needed_flags, cflags, opts);
+        -:  574:
+    #####:  575:	nbd = open(nbddev, O_RDWR);
+    #####:  576:	if (nbd < 0)
+    #####:  577:	  err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
+        -:  578:
+    #####:  579:	setsizes(nbd, size64, blocksize, flags);
+    #####:  580:	set_timeout(nbd, timeout);
+    #####:  581:	finish_sock(sock, nbd, swap);
+    #####:  582:	if (swap) {
+        -:  583:		/* try linux >= 2.6.36 interface first */
+    #####:  584:		if (oom_adjust("/proc/self/oom_score_adj", "-1000")) {
+        -:  585:			/* fall back to linux <= 2.6.35 interface */
+    #####:  586:			oom_adjust("/proc/self/oom_adj", "-17");
+        -:  587:		}
+        -:  588:	}
+        -:  589:
+        -:  590:	/* Go daemon */
+        -:  591:	
+        -:  592:#ifndef NOFORK
+    #####:  593:	if(!nofork) {
+    #####:  594:		if (daemon(0,0) < 0)
+    #####:  595:			err("Cannot detach from terminal");
+        -:  596:	}
+        -:  597:
+    #####:  598:	memset(&sa, 0, sizeof(sa));
+    #####:  599:	sa.sa_handler = SIG_IGN;
+    #####:  600:	sigaction(SIGCHLD, &sa, NULL);
+        -:  601:#endif
+        -:  602:	do {
+        -:  603:#ifndef NOFORK
+        -:  604:
+    #####:  605:		sigfillset(&block);
+    #####:  606:		sigdelset(&block, SIGKILL);
+    #####:  607:		sigdelset(&block, SIGTERM);
+    #####:  608:		sigdelset(&block, SIGPIPE);
+    #####:  609:		sigprocmask(SIG_SETMASK, &block, &old);
+        -:  610:
+    #####:  611:		if (!fork()) {
+        -:  612:			/* Due to a race, the kernel NBD driver cannot
+        -:  613:			 * call for a reread of the partition table
+        -:  614:			 * in the handling of the NBD_DO_IT ioctl().
+        -:  615:			 * Therefore, this is done in the first open()
+        -:  616:			 * of the device. We therefore make sure that
+        -:  617:			 * the device is opened at least once after the
+        -:  618:			 * connection was made. This has to be done in a
+        -:  619:			 * separate process, since the NBD_DO_IT ioctl()
+        -:  620:			 * does not return until the NBD device has
+        -:  621:			 * disconnected.
+        -:  622:			 */
+    #####:  623:			while(check_conn(nbddev, 0)) {
+    #####:  624:				sleep(1);
+        -:  625:			}
+    #####:  626:			open(nbddev, O_RDONLY);
+    #####:  627:			exit(0);
+        -:  628:		}
+        -:  629:#endif
+        -:  630:
+    #####:  631:		if (ioctl(nbd, NBD_DO_IT) < 0) {
+    #####:  632:		        int error = errno;
+    #####:  633:			fprintf(stderr, "nbd,%d: Kernel call returned: %d", getpid(), error);
+    #####:  634:			if(error==EBADR) {
+        -:  635:				/* The user probably did 'nbd-client -d' on us.
+        -:  636:				 * quit */
+    #####:  637:				cont=0;
+        -:  638:			} else {
+    #####:  639:				if(cont) {
+        -:  640:					u64 new_size;
+        -:  641:					u32 new_flags;
+        -:  642:
+    #####:  643:					close(sock); close(nbd);
+        -:  644:					for (;;) {
+    #####:  645:						fprintf(stderr, " Reconnecting\n");
+    #####:  646:						sock = opennet(hostname, port, sdp);
+    #####:  647:						if (sock >= 0)
+    #####:  648:							break;
+    #####:  649:						sleep (1);
+    #####:  650:					}
+    #####:  651:					nbd = open(nbddev, O_RDWR);
+    #####:  652:					if (nbd < 0)
+    #####:  653:						err("Cannot open NBD: %m");
+    #####:  654:					negotiate(sock, &new_size, &new_flags, name, needed_flags, cflags, opts);
+    #####:  655:					if (size64 != new_size) {
+    #####:  656:						err("Size of the device changed. Bye");
+        -:  657:					}
+    #####:  658:					setsizes(nbd, size64, blocksize,
+        -:  659:								new_flags);
+        -:  660:
+    #####:  661:					set_timeout(nbd, timeout);
+    #####:  662:					finish_sock(sock,nbd,swap);
+        -:  663:				}
+        -:  664:			}
+        -:  665:		} else {
+        -:  666:			/* We're on 2.4. It's not clearly defined what exactly
+        -:  667:			 * happened at this point. Probably best to quit, now
+        -:  668:			 */
+    #####:  669:			fprintf(stderr, "Kernel call returned.");
+    #####:  670:			cont=0;
+        -:  671:		}
+    #####:  672:	} while(cont);
+    #####:  673:	printf("sock, ");
+    #####:  674:	ioctl(nbd, NBD_CLEAR_SOCK);
+    #####:  675:	printf("done\n");
+    #####:  676:	return 0;
+        -:  677:}
only in patch2:
unchanged:
--- nbd-3.8.orig/nbd-server.c.gcov
+++ nbd-3.8/nbd-server.c.gcov
@@ -0,0 +1,2809 @@
+        -:    0:Source:nbd-server.c
+        -:    0:Programs:4
+        -:    1:/*
+        -:    2: * Network Block Device - server
+        -:    3: *
+        -:    4: * Copyright 1996-1998 Pavel Machek, distribute under GPL
+        -:    5: *  <pavel@atrey.karlin.mff.cuni.cz>
+        -:    6: * Copyright 2001-2004 Wouter Verhelst <wouter@debian.org>
+        -:    7: * Copyright 2002 Anton Altaparmakov <aia21@cam.ac.uk>
+        -:    8: *
+        -:    9: * Version 1.0 - hopefully 64-bit-clean
+        -:   10: * Version 1.1 - merging enhancements from Josh Parsons, <josh@coombs.anu.edu.au>
+        -:   11: * Version 1.2 - autodetect size of block devices, thanx to Peter T. Breuer" <ptb@it.uc3m.es>
+        -:   12: * Version 1.5 - can compile on Unix systems that don't have 64 bit integer
+        -:   13: *	type, or don't have 64 bit file offsets by defining FS_32BIT
+        -:   14: *	in compile options for nbd-server *only*. This can be done
+        -:   15: *	with make FSCHOICE=-DFS_32BIT nbd-server. (I don't have the
+        -:   16: *	original autoconf input file, or I would make it a configure
+        -:   17: *	option.) Ken Yap <ken@nlc.net.au>.
+        -:   18: * Version 1.6 - fix autodetection of block device size and really make 64 bit
+        -:   19: * 	clean on 32 bit machines. Anton Altaparmakov <aia21@cam.ac.uk>
+        -:   20: * Version 2.0 - Version synchronised with client
+        -:   21: * Version 2.1 - Reap zombie client processes when they exit. Removed
+        -:   22: * 	(uncommented) the _IO magic, it's no longer necessary. Wouter
+        -:   23: * 	Verhelst <wouter@debian.org>
+        -:   24: * Version 2.2 - Auto switch to read-only mode (usefull for floppies).
+        -:   25: * Version 2.3 - Fixed code so that Large File Support works. This
+        -:   26: *	removes the FS_32BIT compile-time directive; define
+        -:   27: *	_FILE_OFFSET_BITS=64 and _LARGEFILE_SOURCE if you used to be
+        -:   28: *	using FS_32BIT. This will allow you to use files >2GB instead of
+        -:   29: *	having to use the -m option. Wouter Verhelst <wouter@debian.org>
+        -:   30: * Version 2.4 - Added code to keep track of children, so that we can
+        -:   31: * 	properly kill them from initscripts. Add a call to daemon(),
+        -:   32: * 	so that processes don't think they have to wait for us, which is
+        -:   33: * 	interesting for initscripts as well. Wouter Verhelst
+        -:   34: * 	<wouter@debian.org>
+        -:   35: * Version 2.5 - Bugfix release: forgot to reset child_arraysize to
+        -:   36: *      zero after fork()ing, resulting in nbd-server going berserk
+        -:   37: *      when it receives a signal with at least one child open. Wouter
+        -:   38: *      Verhelst <wouter@debian.org>
+        -:   39: * 10/10/2003 - Added socket option SO_KEEPALIVE (sf.net bug 819235);
+        -:   40: * 	rectified type of mainloop::size_host (sf.net bugs 814435 and
+        -:   41: * 	817385); close the PID file after writing to it, so that the
+        -:   42: * 	daemon can actually be found. Wouter Verhelst
+        -:   43: * 	<wouter@debian.org>
+        -:   44: * 10/10/2003 - Size of the data "size_host" was wrong and so was not
+        -:   45: *  	correctly put in network endianness. Many types were corrected
+        -:   46: *  	(size_t and off_t instead of int).  <vspaceg@sourceforge.net>
+        -:   47: * Version 2.6 - Some code cleanup.
+        -:   48: * Version 2.7 - Better build system.
+        -:   49: * 11/02/2004 - Doxygenified the source, modularized it a bit. Needs a 
+        -:   50: * 	lot more work, but this is a start. Wouter Verhelst
+        -:   51: * 	<wouter@debian.org>
+        -:   52: * 16/03/2010 - Add IPv6 support.
+        -:   53: *	Kitt Tientanopajai <kitt@kitty.in.th>
+        -:   54: *	Neutron Soutmun <neo.neutron@gmail.com>
+        -:   55: *	Suriya Soutmun <darksolar@gmail.com>
+        -:   56: */
+        -:   57:
+        -:   58:/* Includes LFS defines, which defines behaviours of some of the following
+        -:   59: * headers, so must come before those */
+        -:   60:#include "lfs.h"
+        -:   61:
+        -:   62:#include <assert.h>
+        -:   63:#include <sys/types.h>
+        -:   64:#include <sys/socket.h>
+        -:   65:#include <sys/stat.h>
+        -:   66:#include <sys/select.h>
+        -:   67:#include <sys/wait.h>
+        -:   68:#ifdef HAVE_SYS_IOCTL_H
+        -:   69:#include <sys/ioctl.h>
+        -:   70:#endif
+        -:   71:#include <sys/param.h>
+        -:   72:#ifdef HAVE_SYS_MOUNT_H
+        -:   73:#include <sys/mount.h>
+        -:   74:#endif
+        -:   75:#include <signal.h>
+        -:   76:#include <errno.h>
+        -:   77:#include <libgen.h>
+        -:   78:#include <netinet/tcp.h>
+        -:   79:#include <netinet/in.h>
+        -:   80:#include <netdb.h>
+        -:   81:#include <syslog.h>
+        -:   82:#include <unistd.h>
+        -:   83:#include <stdbool.h>
+        -:   84:#include <stdio.h>
+        -:   85:#include <stdlib.h>
+        -:   86:#include <string.h>
+        -:   87:#include <fcntl.h>
+        -:   88:#if HAVE_FALLOC_PH
+        -:   89:#include <linux/falloc.h>
+        -:   90:#endif
+        -:   91:#include <arpa/inet.h>
+        -:   92:#include <strings.h>
+        -:   93:#include <dirent.h>
+        -:   94:#include <unistd.h>
+        -:   95:#include <getopt.h>
+        -:   96:#include <pwd.h>
+        -:   97:#include <grp.h>
+        -:   98:#include <dirent.h>
+        -:   99:#include <ctype.h>
+        -:  100:
+        -:  101:#include <glib.h>
+        -:  102:
+        -:  103:/* used in cliserv.h, so must come first */
+        -:  104:#define MY_NAME "nbd_server"
+        -:  105:#include "cliserv.h"
+        -:  106:#include "nbd-debug.h"
+        -:  107:#include "netdb-compat.h"
+        -:  108:
+        -:  109:#ifdef WITH_SDP
+        -:  110:#include <sdp_inet.h>
+        -:  111:#endif
+        -:  112:
+        -:  113:/** Default position of the config file */
+        -:  114:#ifndef SYSCONFDIR
+        -:  115:#define SYSCONFDIR "/etc"
+        -:  116:#endif
+        -:  117:#define CFILE SYSCONFDIR "/nbd-server/config"
+        -:  118:
+        -:  119:/** Where our config file actually is */
+        -:  120:gchar* config_file_pos;
+        -:  121:
+        -:  122:/** global flags */
+        -:  123:int glob_flags=0;
+        -:  124:
+        -:  125:/* Whether we should avoid forking */
+        -:  126:int dontfork = 0;
+        -:  127:
+        -:  128:/**
+        -:  129: * The highest value a variable of type off_t can reach. This is a signed
+        -:  130: * integer, so set all bits except for the leftmost one.
+        -:  131: **/
+        -:  132:#define OFFT_MAX ~((off_t)1<<(sizeof(off_t)*8-1))
+        -:  133:#define BUFSIZE ((1024*1024)+sizeof(struct nbd_reply)) /**< Size of buffer that can hold requests */
+        -:  134:#define DIFFPAGESIZE 4096 /**< diff file uses those chunks */
+        -:  135:
+        -:  136:/** Per-export flags: */
+        -:  137:#define F_READONLY 1      /**< flag to tell us a file is readonly */
+        -:  138:#define F_MULTIFILE 2	  /**< flag to tell us a file is exported using -m */
+        -:  139:#define F_COPYONWRITE 4	  /**< flag to tell us a file is exported using
+        -:  140:			    copyonwrite */
+        -:  141:#define F_AUTOREADONLY 8  /**< flag to tell us a file is set to autoreadonly */
+        -:  142:#define F_SPARSE 16	  /**< flag to tell us copyronwrite should use a sparse file */
+        -:  143:#define F_SDP 32	  /**< flag to tell us the export should be done using the Socket Direct Protocol for RDMA */
+        -:  144:#define F_SYNC 64	  /**< Whether to fsync() after a write */
+        -:  145:#define F_FLUSH 128	  /**< Whether server wants FLUSH to be sent by the client */
+        -:  146:#define F_FUA 256	  /**< Whether server wants FUA to be sent by the client */
+        -:  147:#define F_ROTATIONAL 512  /**< Whether server wants the client to implement the elevator algorithm */
+        -:  148:#define F_TEMPORARY 1024  /**< Whether the backing file is temporary and should be created then unlinked */
+        -:  149:#define F_TRIM 2048       /**< Whether server wants TRIM (discard) to be sent by the client */
+        -:  150:#define F_FIXED 4096	  /**< Client supports fixed new-style protocol (and can thus send us extra options */
+        -:  151:
+        -:  152:/** Global flags: */
+        -:  153:#define F_OLDSTYLE 1	  /**< Allow oldstyle (port-based) exports */
+        -:  154:#define F_LIST 2	  /**< Allow clients to list the exports on a server */
+        -:  155:GHashTable *children;
+        -:  156:char pidfname[256]; /**< name of our PID file */
+        -:  157:char pidftemplate[256]; /**< template to be used for the filename of the PID file */
+        -:  158:char default_authname[] = SYSCONFDIR "/nbd-server/allow"; /**< default name of allow file */
+        -:  159:
+        -:  160:#define NEG_INIT	(1 << 0)
+        -:  161:#define NEG_OLD		(1 << 1)
+        -:  162:#define NEG_MODERN	(1 << 2)
+        -:  163:
+        -:  164:#include <nbdsrv.h>
+        -:  165:
+        -:  166:static volatile sig_atomic_t is_sighup_caught; /**< Flag set by SIGHUP
+        -:  167:                                                    handler to mark a
+        -:  168:                                                    reconfiguration
+        -:  169:                                                    request */
+        -:  170:
+        -:  171:GArray* modernsocks;	  /**< Sockets for the modern handler. Not used
+        -:  172:			       if a client was only specified on the
+        -:  173:			       command line; only port used if
+        -:  174:			       oldstyle is set to false (and then the
+        -:  175:			       command-line client isn't used, gna gna).
+        -:  176:			       This may be more than one socket on
+        -:  177:			       systems that don't support serving IPv4
+        -:  178:			       and IPv6 from the same socket (like,
+        -:  179:			       e.g., FreeBSD) */
+        -:  180:
+        -:  181:bool logged_oversized=false;  /**< whether we logged oversized requests already */
+        -:  182:
+        -:  183:/**
+        -:  184: * Variables associated with an open file
+        -:  185: **/
+        -:  186:typedef struct {
+        -:  187:	int fhandle;      /**< file descriptor */
+        -:  188:	off_t startoff;   /**< starting offset of this file */
+        -:  189:} FILE_INFO;
+        -:  190:
+        -:  191:/**
+        -:  192: * Type of configuration file values
+        -:  193: **/
+        -:  194:typedef enum {
+        -:  195:	PARAM_INT,		/**< This parameter is an integer */
+        -:  196:	PARAM_INT64,		/**< This parameter is an integer */
+        -:  197:	PARAM_STRING,		/**< This parameter is a string */
+        -:  198:	PARAM_BOOL,		/**< This parameter is a boolean */
+        -:  199:} PARAM_TYPE;
+        -:  200:
+        -:  201:/**
+        -:  202: * Configuration file values
+        -:  203: **/
+        -:  204:typedef struct {
+        -:  205:	gchar *paramname;	/**< Name of the parameter, as it appears in
+        -:  206:				  the config file */
+        -:  207:	gboolean required;	/**< Whether this is a required (as opposed to
+        -:  208:				  optional) parameter */
+        -:  209:	PARAM_TYPE ptype;	/**< Type of the parameter. */
+        -:  210:	gpointer target;	/**< Pointer to where the data of this
+        -:  211:				  parameter should be written. If ptype is
+        -:  212:				  PARAM_BOOL, the data is or'ed rather than
+        -:  213:				  overwritten. */
+        -:  214:	gint flagval;		/**< Flag mask for this parameter in case ptype
+        -:  215:				  is PARAM_BOOL. */
+        -:  216:} PARAM;
+        -:  217:
+        -:  218:/**
+        -:  219: * Configuration file values of the "generic" section
+        -:  220: **/
+        -:  221:struct generic_conf {
+        -:  222:        gchar *user;            /**< user we run the server as    */
+        -:  223:        gchar *group;           /**< group we run running as      */
+        -:  224:        gchar *modernaddr;      /**< address of the modern socket */
+        -:  225:        gchar *modernport;      /**< port of the modern socket    */
+        -:  226:        gint flags;             /**< global flags                 */
+        -:  227:};
+        -:  228:
+        -:  229:/**
+        -:  230: * Translate a command name into human readable form
+        -:  231: *
+        -:  232: * @param command The command number (after applying NBD_CMD_MASK_COMMAND)
+        -:  233: * @return pointer to the command name
+        -:  234: **/
+        -:  235:static inline const char * getcommandname(uint64_t command) {
+        -:  236:	switch (command) {
+        -:  237:	case NBD_CMD_READ:
+        -:  238:		return "NBD_CMD_READ";
+        -:  239:	case NBD_CMD_WRITE:
+        -:  240:		return "NBD_CMD_WRITE";
+        -:  241:	case NBD_CMD_DISC:
+        -:  242:		return "NBD_CMD_DISC";
+        -:  243:	case NBD_CMD_FLUSH:
+        -:  244:		return "NBD_CMD_FLUSH";
+        -:  245:	case NBD_CMD_TRIM:
+        -:  246:		return "NBD_CMD_TRIM";
+        -:  247:	default:
+        -:  248:		return "UNKNOWN";
+        -:  249:	}
+        -:  250:}
+        -:  251:
+        -:  252:/**
+        -:  253: * Read data from a file descriptor into a buffer
+        -:  254: *
+        -:  255: * @param f a file descriptor
+        -:  256: * @param buf a buffer
+        -:  257: * @param len the number of bytes to be read
+        -:  258: **/
+   182010:  259:static inline void readit(int f, void *buf, size_t len) {
+        -:  260:	ssize_t res;
+   547524:  261:	while (len > 0) {
+        -:  262:		DEBUG("*");
+   183505:  263:		if ((res = read(f, buf, len)) <= 0) {
+        1:  264:			if(errno != EAGAIN) {
+        1:  265:				err("Read failed: %m");
+        -:  266:			}
+        -:  267:		} else {
+   183504:  268:			len -= res;
+   183504:  269:			buf += res;
+        -:  270:		}
+        -:  271:	}
+   182009:  272:}
+        -:  273:
+        -:  274:/**
+        -:  275: * Consume data from an FD that we don't want
+        -:  276: *
+        -:  277: * @param f a file descriptor
+        -:  278: * @param buf a buffer
+        -:  279: * @param len the number of bytes to consume
+        -:  280: * @param bufsiz the size of the buffer
+        -:  281: **/
+    #####:  282:static inline void consume(int f, void * buf, size_t len, size_t bufsiz) {
+        -:  283:	size_t curlen;
+    #####:  284:	while (len>0) {
+    #####:  285:		curlen = (len>bufsiz)?bufsiz:len;
+    #####:  286:		readit(f, buf, curlen);
+    #####:  287:		len -= curlen;
+        -:  288:	}
+    #####:  289:}
+        -:  290:
+        -:  291:/**
+        -:  292: * Write data from a buffer into a filedescriptor
+        -:  293: *
+        -:  294: * @param f a file descriptor
+        -:  295: * @param buf a buffer containing data
+        -:  296: * @param len the number of bytes to be written
+        -:  297: **/
+   134896:  298:static inline void writeit(int f, void *buf, size_t len) {
+        -:  299:	ssize_t res;
+   404688:  300:	while (len > 0) {
+        -:  301:		DEBUG("+");
+   134896:  302:		if ((res = write(f, buf, len)) <= 0)
+    #####:  303:			err("Send failed: %m");
+   134896:  304:		len -= res;
+   134896:  305:		buf += res;
+        -:  306:	}
+   134896:  307:}
+        -:  308:
+        -:  309:/**
+        -:  310: * Print out a message about how to use nbd-server. Split out to a separate
+        -:  311: * function so that we can call it from multiple places
+        -:  312: */
+    #####:  313:void usage() {
+    #####:  314:	printf("This is nbd-server version " VERSION "\n");
+    #####:  315:	printf("Usage: [ip:|ip6@]port file_to_export [size][kKmM] [-l authorize_file] [-r] [-m] [-c] [-C configuration file] [-p PID file name] [-o section name] [-M max connections] [-V]\n"
+        -:  316:	       "\t-r|--read-only\t\tread only\n"
+        -:  317:	       "\t-m|--multi-file\t\tmultiple file\n"
+        -:  318:	       "\t-c|--copy-on-write\tcopy on write\n"
+        -:  319:	       "\t-C|--config-file\tspecify an alternate configuration file\n"
+        -:  320:	       "\t-l|--authorize-file\tfile with list of hosts that are allowed to\n\t\t\t\tconnect.\n"
+        -:  321:	       "\t-p|--pid-file\t\tspecify a filename to write our PID to\n"
+        -:  322:	       "\t-o|--output-config\toutput a config file section for what you\n\t\t\t\tspecified on the command line, with the\n\t\t\t\tspecified section name\n"
+        -:  323:	       "\t-M|--max-connections\tspecify the maximum number of opened connections\n"
+        -:  324:	       "\t-V|--version\toutput the version and exit\n\n"
+        -:  325:	       "\tif port is set to 0, stdin is used (for running from inetd).\n"
+        -:  326:	       "\tif file_to_export contains '%%s', it is substituted with the IP\n"
+        -:  327:	       "\t\taddress of the machine trying to connect\n" 
+        -:  328:	       "\tif ip is set, it contains the local IP address on which we're listening.\n\tif not, the server will listen on all local IP addresses\n");
+    #####:  329:	printf("Using configuration file %s\n", CFILE);
+    #####:  330:}
+        -:  331:
+        -:  332:/* Dumps a config file section of the given SERVER*, and exits. */
+    #####:  333:void dump_section(SERVER* serve, gchar* section_header) {
+    #####:  334:	printf("[%s]\n", section_header);
+    #####:  335:	printf("\texportname = %s\n", serve->exportname);
+    #####:  336:	printf("\tlistenaddr = %s\n", serve->listenaddr);
+    #####:  337:	printf("\tport = %d\n", serve->port);
+    #####:  338:	if(serve->flags & F_READONLY) {
+    #####:  339:		printf("\treadonly = true\n");
+        -:  340:	}
+    #####:  341:	if(serve->flags & F_MULTIFILE) {
+    #####:  342:		printf("\tmultifile = true\n");
+        -:  343:	}
+    #####:  344:	if(serve->flags & F_COPYONWRITE) {
+    #####:  345:		printf("\tcopyonwrite = true\n");
+        -:  346:	}
+    #####:  347:	if(serve->expected_size) {
+    #####:  348:		printf("\tfilesize = %lld\n", (long long int)serve->expected_size);
+        -:  349:	}
+    #####:  350:	if(serve->authname) {
+    #####:  351:		printf("\tauthfile = %s\n", serve->authname);
+        -:  352:	}
+    #####:  353:	exit(EXIT_SUCCESS);
+        -:  354:}
+        -:  355:
+        -:  356:/**
+        -:  357: * Parse the command line.
+        -:  358: *
+        -:  359: * @param argc the argc argument to main()
+        -:  360: * @param argv the argv argument to main()
+        -:  361: **/
+       10:  362:SERVER* cmdline(int argc, char *argv[]) {
+       10:  363:	int i=0;
+       10:  364:	int nonspecial=0;
+        -:  365:	int c;
+       10:  366:	struct option long_options[] = {
+        -:  367:		{"read-only", no_argument, NULL, 'r'},
+        -:  368:		{"multi-file", no_argument, NULL, 'm'},
+        -:  369:		{"copy-on-write", no_argument, NULL, 'c'},
+        -:  370:		{"dont-fork", no_argument, NULL, 'd'},
+        -:  371:		{"authorize-file", required_argument, NULL, 'l'},
+        -:  372:		{"config-file", required_argument, NULL, 'C'},
+        -:  373:		{"pid-file", required_argument, NULL, 'p'},
+        -:  374:		{"output-config", required_argument, NULL, 'o'},
+        -:  375:		{"max-connection", required_argument, NULL, 'M'},
+        -:  376:		{"version", no_argument, NULL, 'V'},
+        -:  377:		{0,0,0,0}
+        -:  378:	};
+        -:  379:	SERVER *serve;
+        -:  380:	off_t es;
+        -:  381:	size_t last;
+        -:  382:	char suffix;
+       10:  383:	gboolean do_output=FALSE;
+       10:  384:	gchar* section_header="";
+        -:  385:	gchar** addr_port;
+        -:  386:
+       10:  387:	if(argc==1) {
+    #####:  388:		return NULL;
+        -:  389:	}
+       10:  390:	serve=g_new0(SERVER, 1);
+       10:  391:	serve->authname = g_strdup(default_authname);
+       10:  392:	serve->virtstyle=VIRT_IPLIT;
+       44:  393:	while((c=getopt_long(argc, argv, "-C:cdl:mo:rp:M:V", long_options, &i))>=0) {
+       24:  394:		switch (c) {
+        -:  395:		case 1:
+        -:  396:			/* non-option argument */
+        4:  397:			switch(nonspecial++) {
+        -:  398:			case 0:
+        2:  399:				if(strchr(optarg, ':') == strrchr(optarg, ':')) {
+        2:  400:					addr_port=g_strsplit(optarg, ":", 2);
+        -:  401:
+        -:  402:					/* Check for "@" - maybe user using this separator
+        -:  403:						 for IPv4 address */
+        2:  404:					if(!addr_port[1]) {
+        2:  405:						g_strfreev(addr_port);
+        2:  406:						addr_port=g_strsplit(optarg, "@", 2);
+        -:  407:					}
+        -:  408:				} else {
+    #####:  409:					addr_port=g_strsplit(optarg, "@", 2);
+        -:  410:				}
+        -:  411:
+        2:  412:				if(addr_port[1]) {
+    #####:  413:					serve->port=strtol(addr_port[1], NULL, 0);
+    #####:  414:					serve->listenaddr=g_strdup(addr_port[0]);
+        -:  415:				} else {
+        2:  416:					serve->listenaddr=NULL;
+        2:  417:					serve->port=strtol(addr_port[0], NULL, 0);
+        -:  418:				}
+        2:  419:				g_strfreev(addr_port);
+        2:  420:				break;
+        -:  421:			case 1:
+        2:  422:				serve->exportname = g_strdup(optarg);
+        2:  423:				if(serve->exportname[0] != '/') {
+    #####:  424:					fprintf(stderr, "E: The to be exported file needs to be an absolute filename!\n");
+    #####:  425:					exit(EXIT_FAILURE);
+        -:  426:				}
+        2:  427:				break;
+        -:  428:			case 2:
+    #####:  429:				last=strlen(optarg)-1;
+    #####:  430:				suffix=optarg[last];
+    #####:  431:				if (suffix == 'k' || suffix == 'K' ||
+    #####:  432:				    suffix == 'm' || suffix == 'M')
+    #####:  433:					optarg[last] = '\0';
+    #####:  434:				es = (off_t)atoll(optarg);
+    #####:  435:				switch (suffix) {
+        -:  436:					case 'm':
+    #####:  437:					case 'M':  es <<= 10;
+        -:  438:					case 'k':
+    #####:  439:					case 'K':  es <<= 10;
+    #####:  440:					default :  break;
+        -:  441:				}
+    #####:  442:				serve->expected_size = es;
+    #####:  443:				break;
+        -:  444:			}
+        4:  445:			break;
+        -:  446:		case 'r':
+    #####:  447:			serve->flags |= F_READONLY;
+    #####:  448:			break;
+        -:  449:		case 'm':
+    #####:  450:			serve->flags |= F_MULTIFILE;
+    #####:  451:			break;
+        -:  452:		case 'o':
+    #####:  453:			do_output = TRUE;
+    #####:  454:			section_header = g_strdup(optarg);
+    #####:  455:			break;
+        -:  456:		case 'p':
+       10:  457:			strncpy(pidftemplate, optarg, 256);
+       10:  458:			pidftemplate[255]='\0';
+       10:  459:			break;
+        -:  460:		case 'c': 
+    #####:  461:			serve->flags |=F_COPYONWRITE;
+    #####:  462:		        break;
+        -:  463:		case 'd': 
+    #####:  464:			dontfork = 1;
+    #####:  465:		        break;
+        -:  466:		case 'C':
+       10:  467:			g_free(config_file_pos);
+       10:  468:			config_file_pos=g_strdup(optarg);
+       10:  469:			break;
+        -:  470:		case 'l':
+    #####:  471:			g_free(serve->authname);
+    #####:  472:			serve->authname=g_strdup(optarg);
+    #####:  473:			break;
+        -:  474:		case 'M':
+    #####:  475:			serve->max_connections = strtol(optarg, NULL, 0);
+    #####:  476:			break;
+        -:  477:		case 'V':
+    #####:  478:			printf("This is nbd-server version " VERSION "\n");
+    #####:  479:			exit(EXIT_SUCCESS);
+        -:  480:			break;
+        -:  481:		default:
+    #####:  482:			usage();
+    #####:  483:			exit(EXIT_FAILURE);
+        -:  484:			break;
+        -:  485:		}
+        -:  486:	}
+        -:  487:	/* What's left: the port to export, the name of the to be exported
+        -:  488:	 * file, and, optionally, the size of the file, in that order. */
+       10:  489:	if(nonspecial<2) {
+        8:  490:		g_free(serve);
+        8:  491:		serve=NULL;
+        -:  492:	} else {
+        2:  493:		glob_flags |= F_OLDSTYLE;
+        -:  494:	}
+       10:  495:	if(do_output) {
+    #####:  496:		if(!serve) {
+    #####:  497:			g_critical("Need a complete configuration on the command line to output a config file section!");
+    #####:  498:			exit(EXIT_FAILURE);
+        -:  499:		}
+    #####:  500:		dump_section(serve, section_header);
+        -:  501:	}
+       10:  502:	return serve;
+        -:  503:}
+        -:  504:
+        -:  505:/* forward definition of parse_cfile */
+        -:  506:GArray* parse_cfile(gchar* f, struct generic_conf *genconf, bool expect_generic, GError** e);
+        -:  507:
+        -:  508:/**
+        -:  509: * Parse config file snippets in a directory. Uses readdir() and friends
+        -:  510: * to find files and open them, then passes them on to parse_cfile
+        -:  511: * with have_global set false
+        -:  512: **/
+        1:  513:GArray* do_cfile_dir(gchar* dir, struct generic_conf *const genconf, GError** e) {
+        1:  514:	DIR* dirh = opendir(dir);
+        -:  515:	struct dirent* de;
+        -:  516:	gchar* fname;
+        1:  517:	GArray* retval = NULL;
+        -:  518:	GArray* tmp;
+        -:  519:	struct stat stbuf;
+        -:  520:
+        1:  521:	if(!dirh) {
+    #####:  522:		g_set_error(e, NBDS_ERR, NBDS_ERR_CFILE_DIR_UNKNOWN, "Invalid directory specified: %s", strerror(errno));
+    #####:  523:		return NULL;
+        -:  524:	}
+        1:  525:	errno=0;
+        5:  526:	while((de = readdir(dirh))) {
+        3:  527:		int saved_errno=errno;
+        3:  528:		fname = g_build_filename(dir, de->d_name, NULL);
+        3:  529:		switch(de->d_type) {
+        -:  530:			case DT_UNKNOWN:
+        -:  531:				/* Filesystem doesn't return type of
+        -:  532:				 * file through readdir. Run stat() on
+        -:  533:				 * the file instead */
+    #####:  534:				if(stat(fname, &stbuf)) {
+    #####:  535:					perror("stat");
+    #####:  536:					goto err_out;
+        -:  537:				}
+    #####:  538:				if (!S_ISREG(stbuf.st_mode)) {
+    #####:  539:					goto next;
+        -:  540:				}
+        -:  541:			case DT_REG:
+        -:  542:				/* Skip unless the name ends with '.conf' */
+        1:  543:				if(strcmp((de->d_name + strlen(de->d_name) - 5), ".conf")) {
+    #####:  544:					goto next;
+        -:  545:				}
+        1:  546:				tmp = parse_cfile(fname, genconf, false, e);
+        1:  547:				errno=saved_errno;
+        1:  548:				if(*e) {
+    #####:  549:					goto err_out;
+        -:  550:				}
+        1:  551:				if(!retval)
+        1:  552:					retval = g_array_new(FALSE, TRUE, sizeof(SERVER));
+        1:  553:				retval = g_array_append_vals(retval, tmp->data, tmp->len);
+        1:  554:				g_array_free(tmp, TRUE);
+        -:  555:			default:
+        3:  556:				break;
+        -:  557:		}
+        -:  558:	next:
+        3:  559:		g_free(fname);
+        -:  560:	}
+        1:  561:	if(errno) {
+    #####:  562:		g_set_error(e, NBDS_ERR, NBDS_ERR_CFILE_READDIR_ERR, "Error trying to read directory: %s", strerror(errno));
+        -:  563:	err_out:
+    #####:  564:		if(retval)
+    #####:  565:			g_array_free(retval, TRUE);
+    #####:  566:		if(dirh)
+    #####:  567:			closedir(dirh);
+    #####:  568:		return NULL;
+        -:  569:	}
+        1:  570:	return retval;
+        -:  571:}
+        -:  572:
+       11:  573:static bool want_oldstyle(struct generic_conf gct, struct generic_conf* gc) {
+       11:  574:	if(gct.flags & F_OLDSTYLE) {
+        5:  575:		return true;
+        -:  576:	}
+        6:  577:	if(gc == NULL) {
+    #####:  578:		return false;
+        -:  579:	}
+        6:  580:	if(gc->flags & F_OLDSTYLE) {
+    #####:  581:		return true;
+        -:  582:	}
+        6:  583:	return false;
+        -:  584:}
+        -:  585:/**
+        -:  586: * Parse the config file.
+        -:  587: *
+        -:  588: * @param f the name of the config file
+        -:  589: *
+        -:  590: * @param genconf a pointer to generic configuration which will get
+        -:  591: *        updated with parsed values. If NULL, then parsed generic
+        -:  592: *        configuration values are safely and silently discarded.
+        -:  593: *
+        -:  594: * @param e a GError. Error code can be any of the following:
+        -:  595: *        NBDS_ERR_CFILE_NOTFOUND, NBDS_ERR_CFILE_MISSING_GENERIC,
+        -:  596: *        NBDS_ERR_CFILE_VALUE_INVALID, NBDS_ERR_CFILE_VALUE_UNSUPPORTED
+        -:  597: *        or NBDS_ERR_CFILE_NO_EXPORTS. @see NBDS_ERRS.
+        -:  598: *
+        -:  599: * @param expect_generic if true, we expect a configuration file that
+        -:  600: * 	  contains a [generic] section. If false, we don't.
+        -:  601: *
+        -:  602: * @return a GArray of SERVER* pointers. If the config file is empty or does not
+        -:  603: *	exist, returns an empty GArray; if the config file contains an
+        -:  604: *	error, returns NULL, and e is set appropriately
+        -:  605: **/
+       11:  606:GArray* parse_cfile(gchar* f, struct generic_conf *const genconf, bool expect_generic, GError** e) {
+       11:  607:	const char* DEFAULT_ERROR = "Could not parse %s in group %s: %s";
+       11:  608:	const char* MISSING_REQUIRED_ERROR = "Could not find required value %s in group %s: %s";
+       11:  609:	gchar* cfdir = NULL;
+        -:  610:	SERVER s;
+       11:  611:	gchar *virtstyle=NULL;
+       11:  612:	PARAM lp[] = {
+        -:  613:		{ "exportname", TRUE,	PARAM_STRING, 	&(s.exportname),	0 },
+        -:  614:		{ "port", 	TRUE,	PARAM_INT, 	&(s.port),		0 },
+        -:  615:		{ "authfile",	FALSE,	PARAM_STRING,	&(s.authname),		0 },
+        -:  616:		{ "filesize",	FALSE,	PARAM_OFFT,	&(s.expected_size),	0 },
+        -:  617:		{ "virtstyle",	FALSE,	PARAM_STRING,	&(virtstyle),		0 },
+        -:  618:		{ "prerun",	FALSE,	PARAM_STRING,	&(s.prerun),		0 },
+        -:  619:		{ "postrun",	FALSE,	PARAM_STRING,	&(s.postrun),		0 },
+        -:  620:		{ "transactionlog", FALSE, PARAM_STRING, &(s.transactionlog),	0 },
+        -:  621:		{ "cowdir",	FALSE,	PARAM_STRING,	&(s.cowdir),		0 },
+        -:  622:		{ "readonly",	FALSE,	PARAM_BOOL,	&(s.flags),		F_READONLY },
+        -:  623:		{ "multifile",	FALSE,	PARAM_BOOL,	&(s.flags),		F_MULTIFILE },
+        -:  624:		{ "copyonwrite", FALSE,	PARAM_BOOL,	&(s.flags),		F_COPYONWRITE },
+        -:  625:		{ "sparse_cow",	FALSE,	PARAM_BOOL,	&(s.flags),		F_SPARSE },
+        -:  626:		{ "sdp",	FALSE,	PARAM_BOOL,	&(s.flags),		F_SDP },
+        -:  627:		{ "sync",	FALSE,  PARAM_BOOL,	&(s.flags),		F_SYNC },
+        -:  628:		{ "flush",	FALSE,  PARAM_BOOL,	&(s.flags),		F_FLUSH },
+        -:  629:		{ "fua",	FALSE,  PARAM_BOOL,	&(s.flags),		F_FUA },
+        -:  630:		{ "rotational",	FALSE,  PARAM_BOOL,	&(s.flags),		F_ROTATIONAL },
+        -:  631:		{ "temporary",	FALSE,  PARAM_BOOL,	&(s.flags),		F_TEMPORARY },
+        -:  632:		{ "trim",	FALSE,  PARAM_BOOL,	&(s.flags),		F_TRIM },
+        -:  633:		{ "listenaddr", FALSE,  PARAM_STRING,   &(s.listenaddr),	0 },
+        -:  634:		{ "maxconnections", FALSE, PARAM_INT,	&(s.max_connections),	0 },
+        -:  635:	};
+       11:  636:	const int lp_size=sizeof(lp)/sizeof(PARAM);
+        -:  637:        struct generic_conf genconftmp;
+       11:  638:	PARAM gp[] = {
+        -:  639:		{ "user",	FALSE, PARAM_STRING,	&(genconftmp.user),       0 },
+        -:  640:		{ "group",	FALSE, PARAM_STRING,	&(genconftmp.group),      0 },
+        -:  641:		{ "oldstyle",	FALSE, PARAM_BOOL,	&(genconftmp.flags),      F_OLDSTYLE },
+        -:  642:		{ "listenaddr", FALSE, PARAM_STRING,	&(genconftmp.modernaddr), 0 },
+        -:  643:		{ "port", 	FALSE, PARAM_STRING,	&(genconftmp.modernport), 0 },
+        -:  644:		{ "includedir", FALSE, PARAM_STRING,	&cfdir,                   0 },
+        -:  645:		{ "allowlist",  FALSE, PARAM_BOOL,	&(genconftmp.flags),      F_LIST },
+        -:  646:	};
+       11:  647:	PARAM* p=gp;
+       11:  648:	int p_size=sizeof(gp)/sizeof(PARAM);
+        -:  649:	GKeyFile *cfile;
+       11:  650:	GError *err = NULL;
+       11:  651:	const char *err_msg=NULL;
+       11:  652:	GArray *retval=NULL;
+        -:  653:	gchar **groups;
+        -:  654:	gboolean bval;
+        -:  655:	gint ival;
+        -:  656:	gint64 i64val;
+        -:  657:	gchar* sval;
+        -:  658:	gchar* startgroup;
+        -:  659:	gint i;
+        -:  660:	gint j;
+        -:  661:
+       11:  662:        memset(&genconftmp, 0, sizeof(struct generic_conf));
+        -:  663:
+       11:  664:        if (genconf) {
+        -:  665:                /* Use the passed configuration values as defaults. The
+        -:  666:                 * parsing algorithm below updates all parameter targets
+        -:  667:                 * found from configuration files. */
+       11:  668:                memcpy(&genconftmp, genconf, sizeof(struct generic_conf));
+        -:  669:        }
+        -:  670:
+       11:  671:	cfile = g_key_file_new();
+       11:  672:	retval = g_array_new(FALSE, TRUE, sizeof(SERVER));
+       11:  673:	if(!g_key_file_load_from_file(cfile, f, G_KEY_FILE_KEEP_COMMENTS |
+        -:  674:			G_KEY_FILE_KEEP_TRANSLATIONS, &err)) {
+        2:  675:		g_set_error(e, NBDS_ERR, NBDS_ERR_CFILE_NOTFOUND, "Could not open config file %s: %s",
+        2:  676:				f, err->message);
+        2:  677:		g_key_file_free(cfile);
+        2:  678:		return retval;
+        -:  679:	}
+        9:  680:	startgroup = g_key_file_get_start_group(cfile);
+        9:  681:	if((!startgroup || strcmp(startgroup, "generic")) && expect_generic) {
+    #####:  682:		g_set_error(e, NBDS_ERR, NBDS_ERR_CFILE_MISSING_GENERIC, "Config file does not contain the [generic] group!");
+    #####:  683:		g_key_file_free(cfile);
+    #####:  684:		return NULL;
+        -:  685:	}
+        9:  686:	groups = g_key_file_get_groups(cfile, NULL);
+       26:  687:	for(i=0;groups[i];i++) {
+       17:  688:		memset(&s, '\0', sizeof(SERVER));
+        -:  689:
+        -:  690:		/* After the [generic] group or when we're parsing an include
+        -:  691:		 * directory, start parsing exports */
+       17:  692:		if(i==1 || !expect_generic) {
+        8:  693:			p=lp;
+        8:  694:			p_size=lp_size;
+        8:  695:			if(!want_oldstyle(genconftmp, genconf)) {
+        6:  696:				lp[1].required = FALSE;
+        -:  697:			}
+        -:  698:		} 
+      271:  699:		for(j=0;j<p_size;j++) {
+      254:  700:			assert(p[j].target != NULL);
+      254:  701:			assert(p[j].ptype==PARAM_INT||p[j].ptype==PARAM_STRING||p[j].ptype==PARAM_BOOL||p[j].ptype==PARAM_INT64);
+      254:  702:			switch(p[j].ptype) {
+        -:  703:				case PARAM_INT:
+       18:  704:					ival = g_key_file_get_integer(cfile,
+       18:  705:								groups[i],
+       18:  706:								p[j].paramname,
+        -:  707:								&err);
+       18:  708:					if(!err) {
+        3:  709:						*((gint*)p[j].target) = ival;
+        -:  710:					}
+       18:  711:					break;
+        -:  712:				case PARAM_INT64:
+        9:  713:					i64val = g_key_file_get_int64(cfile,
+        9:  714:								groups[i],
+        9:  715:								p[j].paramname,
+        -:  716:								&err);
+        9:  717:					if(!err) {
+        1:  718:						*((gint64*)p[j].target) = i64val;
+        -:  719:					}
+        9:  720:					break;
+        -:  721:				case PARAM_STRING:
+      112:  722:					sval = g_key_file_get_string(cfile,
+      112:  723:								groups[i],
+      112:  724:								p[j].paramname,
+        -:  725:								&err);
+      112:  726:					if(!err) {
+       13:  727:						*((gchar**)p[j].target) = sval;
+        -:  728:					}
+      112:  729:					break;
+        -:  730:				case PARAM_BOOL:
+      115:  731:					bval = g_key_file_get_boolean(cfile,
+      115:  732:							groups[i],
+      115:  733:							p[j].paramname, &err);
+      115:  734:					if(!err) {
+       13:  735:						if(bval) {
+       13:  736:							*((gint*)p[j].target) |= p[j].flagval;
+        -:  737:						} else {
+    #####:  738:							*((gint*)p[j].target) &= ~(p[j].flagval);
+        -:  739:						}
+        -:  740:					}
+      115:  741:					break;
+        -:  742:			}
+      254:  743:			if(err) {
+      224:  744:				if(err->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
+      224:  745:					if(!p[j].required) {
+        -:  746:						/* Ignore not-found error for optional values */
+      224:  747:						g_clear_error(&err);
+      224:  748:						continue;
+        -:  749:					} else {
+    #####:  750:						err_msg = MISSING_REQUIRED_ERROR;
+        -:  751:					}
+        -:  752:				} else {
+    #####:  753:					err_msg = DEFAULT_ERROR;
+        -:  754:				}
+    #####:  755:				g_set_error(e, NBDS_ERR, NBDS_ERR_CFILE_VALUE_INVALID, err_msg, p[j].paramname, groups[i], err->message);
+    #####:  756:				g_array_free(retval, TRUE);
+    #####:  757:				g_error_free(err);
+    #####:  758:				g_key_file_free(cfile);
+    #####:  759:				return NULL;
+        -:  760:			}
+        -:  761:		}
+       17:  762:		if(virtstyle) {
+    #####:  763:			if(!strncmp(virtstyle, "none", 4)) {
+    #####:  764:				s.virtstyle=VIRT_NONE;
+    #####:  765:			} else if(!strncmp(virtstyle, "ipliteral", 9)) {
+    #####:  766:				s.virtstyle=VIRT_IPLIT;
+    #####:  767:			} else if(!strncmp(virtstyle, "iphash", 6)) {
+    #####:  768:				s.virtstyle=VIRT_IPHASH;
+    #####:  769:			} else if(!strncmp(virtstyle, "cidrhash", 8)) {
+    #####:  770:				s.virtstyle=VIRT_CIDR;
+    #####:  771:				if(strlen(virtstyle)<10) {
+    #####:  772:					g_set_error(e, NBDS_ERR, NBDS_ERR_CFILE_VALUE_INVALID, "Invalid value %s for parameter virtstyle in group %s: missing length", virtstyle, groups[i]);
+    #####:  773:					g_array_free(retval, TRUE);
+    #####:  774:					g_key_file_free(cfile);
+    #####:  775:					return NULL;
+        -:  776:				}
+    #####:  777:				s.cidrlen=strtol(virtstyle+8, NULL, 0);
+        -:  778:			} else {
+    #####:  779:				g_set_error(e, NBDS_ERR, NBDS_ERR_CFILE_VALUE_INVALID, "Invalid value %s for parameter virtstyle in group %s", virtstyle, groups[i]);
+    #####:  780:				g_array_free(retval, TRUE);
+    #####:  781:				g_key_file_free(cfile);
+    #####:  782:				return NULL;
+        -:  783:			}
+        -:  784:		} else {
+       17:  785:			s.virtstyle=VIRT_IPLIT;
+        -:  786:		}
+       17:  787:		if(s.port && !want_oldstyle(genconftmp, genconf)) {
+    #####:  788:			g_warning("A port was specified, but oldstyle exports were not requested. This may not do what you expect.");
+    #####:  789:			g_warning("Please read 'man 5 nbd-server' and search for oldstyle for more info");
+        -:  790:		}
+        -:  791:		/* Don't need to free this, it's not our string */
+       17:  792:		virtstyle=NULL;
+        -:  793:		/* Don't append values for the [generic] group */
+       17:  794:		if(i>0 || !expect_generic) {
+        9:  795:			s.socket_family = AF_UNSPEC;
+        9:  796:			s.servename = groups[i];
+        -:  797:
+        9:  798:			append_serve(&s, retval);
+        -:  799:		}
+        -:  800:#ifndef WITH_SDP
+       17:  801:		if(s.flags & F_SDP) {
+    #####:  802:			g_set_error(e, NBDS_ERR, NBDS_ERR_CFILE_VALUE_UNSUPPORTED, "This nbd-server was built without support for SDP, yet group %s uses it", groups[i]);
+    #####:  803:			g_array_free(retval, TRUE);
+    #####:  804:			g_key_file_free(cfile);
+    #####:  805:			return NULL;
+        -:  806:		}
+        -:  807:#endif
+        -:  808:	}
+        9:  809:	g_key_file_free(cfile);
+        9:  810:	if(cfdir) {
+        1:  811:		GArray* extra = do_cfile_dir(cfdir, &genconftmp, e);
+        1:  812:		if(extra) {
+        1:  813:			retval = g_array_append_vals(retval, extra->data, extra->len);
+        1:  814:			i+=extra->len;
+        1:  815:			g_array_free(extra, TRUE);
+        -:  816:		} else {
+    #####:  817:			if(*e) {
+    #####:  818:				g_array_free(retval, TRUE);
+    #####:  819:				return NULL;
+        -:  820:			}
+        -:  821:		}
+        -:  822:	}
+        9:  823:	if(i==1 && expect_generic) {
+    #####:  824:		g_set_error(e, NBDS_ERR, NBDS_ERR_CFILE_NO_EXPORTS, "The config file does not specify any exports");
+        -:  825:	}
+        -:  826:
+        9:  827:        if (genconf) {
+        -:  828:                /* Return the updated generic configuration through the
+        -:  829:                 * pointer parameter. */
+        9:  830:                memcpy(genconf, &genconftmp, sizeof(struct generic_conf));
+        -:  831:        }
+        -:  832:
+        9:  833:	return retval;
+        -:  834:}
+        -:  835:
+        -:  836:/**
+        -:  837: * Signal handler for SIGCHLD
+        -:  838: * @param s the signal we're handling (must be SIGCHLD, or something
+        -:  839: * is severely wrong)
+        -:  840: **/
+       11:  841:void sigchld_handler(int s) {
+        -:  842:        int status;
+        -:  843:	int* i;
+        -:  844:	pid_t pid;
+        -:  845:
+       33:  846:	while((pid=waitpid(-1, &status, WNOHANG)) > 0) {
+       11:  847:		if(WIFEXITED(status)) {
+       11:  848:			msg(LOG_INFO, "Child exited with %d", WEXITSTATUS(status));
+        -:  849:		}
+       11:  850:		i=g_hash_table_lookup(children, &pid);
+       11:  851:		if(!i) {
+    #####:  852:			msg(LOG_INFO, "SIGCHLD received for an unknown child with PID %ld", (long)pid);
+        -:  853:		} else {
+        -:  854:			DEBUG("Removing %d from the list of children", pid);
+       11:  855:			g_hash_table_remove(children, &pid);
+        -:  856:		}
+        -:  857:	}
+       11:  858:}
+        -:  859:
+        -:  860:/**
+        -:  861: * Kill a child. Called from sigterm_handler::g_hash_table_foreach.
+        -:  862: *
+        -:  863: * @param key the key
+        -:  864: * @param value the value corresponding to the above key
+        -:  865: * @param user_data a pointer which we always set to 1, so that we know what
+        -:  866: * will happen next.
+        -:  867: **/
+        1:  868:void killchild(gpointer key, gpointer value, gpointer user_data) {
+        1:  869:	pid_t *pid=value;
+        -:  870:
+        1:  871:	kill(*pid, SIGTERM);
+        1:  872:}
+        -:  873:
+        -:  874:/**
+        -:  875: * Handle SIGTERM and dispatch it to our children
+        -:  876: * @param s the signal we're handling (must be SIGTERM, or something
+        -:  877: * is severely wrong).
+        -:  878: **/
+       10:  879:void sigterm_handler(int s) {
+       10:  880:	g_hash_table_foreach(children, killchild, NULL);
+       10:  881:	unlink(pidfname);
+        -:  882:
+       10:  883:	exit(EXIT_SUCCESS);
+        -:  884:}
+        -:  885:
+        -:  886:/**
+        -:  887: * Handle SIGHUP by setting atomically a flag which will be evaluated in
+        -:  888: * the main loop of the root server process. This allows us to separate
+        -:  889: * the signal catching from th actual task triggered by SIGHUP and hence
+        -:  890: * processing in the interrupt context is kept as minimial as possible.
+        -:  891: *
+        -:  892: * @param s the signal we're handling (must be SIGHUP, or something
+        -:  893: * is severely wrong).
+        -:  894: **/
+    #####:  895:static void sighup_handler(const int s G_GNUC_UNUSED) {
+    #####:  896:        is_sighup_caught = 1;
+    #####:  897:}
+        -:  898:
+        -:  899:/**
+        -:  900: * Get the file handle and offset, given an export offset.
+        -:  901: *
+        -:  902: * @param export An array of export files
+        -:  903: * @param a The offset to get corresponding file/offset for
+        -:  904: * @param fhandle [out] File descriptor
+        -:  905: * @param foffset [out] Offset into fhandle
+        -:  906: * @param maxbytes [out] Tells how many bytes can be read/written
+        -:  907: * from fhandle starting at foffset (0 if there is no limit)
+        -:  908: * @return 0 on success, -1 on failure
+        -:  909: **/
+   104669:  910:int get_filepos(GArray* export, off_t a, int* fhandle, off_t* foffset, size_t* maxbytes ) {
+        -:  911:	/* Negative offset not allowed */
+   104669:  912:	if(a < 0)
+    #####:  913:		return -1;
+        -:  914:
+        -:  915:	/* Binary search for last file with starting offset <= a */
+        -:  916:	FILE_INFO fi;
+   104669:  917:	int start = 0;
+   104669:  918:	int end = export->len - 1;
+   313995:  919:	while( start <= end ) {
+   104669:  920:		int mid = (start + end) / 2;
+   104669:  921:		fi = g_array_index(export, FILE_INFO, mid);
+   104669:  922:		if( fi.startoff < a ) {
+   104657:  923:			start = mid + 1;
+       12:  924:		} else if( fi.startoff > a ) {
+    #####:  925:			end = mid - 1;
+        -:  926:		} else {
+       12:  927:			start = end = mid;
+       12:  928:			break;
+        -:  929:		}
+        -:  930:	}
+        -:  931:
+        -:  932:	/* end should never go negative, since first startoff is 0 and a >= 0 */
+   104669:  933:	assert(end >= 0);
+        -:  934:
+   104669:  935:	fi = g_array_index(export, FILE_INFO, end);
+   104669:  936:	*fhandle = fi.fhandle;
+   104669:  937:	*foffset = a - fi.startoff;
+   104669:  938:	*maxbytes = 0;
+   104669:  939:	if( end+1 < export->len ) {
+    #####:  940:		FILE_INFO fi_next = g_array_index(export, FILE_INFO, end+1);
+    #####:  941:		*maxbytes = fi_next.startoff - a;
+        -:  942:	}
+        -:  943:
+   104669:  944:	return 0;
+        -:  945:}
+        -:  946:
+        -:  947:/**
+        -:  948: * seek to a position in a file, with error handling.
+        -:  949: * @param handle a filedescriptor
+        -:  950: * @param a position to seek to
+        -:  951: * @todo get rid of this.
+        -:  952: **/
+   104669:  953:void myseek(int handle,off_t a) {
+   104669:  954:	if (lseek(handle, a, SEEK_SET) < 0) {
+    #####:  955:		err("Can not seek locally!\n");
+        -:  956:	}
+   104669:  957:}
+        -:  958:
+        -:  959:/**
+        -:  960: * Write an amount of bytes at a given offset to the right file. This
+        -:  961: * abstracts the write-side of the multiple file option.
+        -:  962: *
+        -:  963: * @param a The offset where the write should start
+        -:  964: * @param buf The buffer to write from
+        -:  965: * @param len The length of buf
+        -:  966: * @param client The client we're serving for
+        -:  967: * @param fua Flag to indicate 'Force Unit Access'
+        -:  968: * @return The number of bytes actually written, or -1 in case of an error
+        -:  969: **/
+    75886:  970:ssize_t rawexpwrite(off_t a, char *buf, size_t len, CLIENT *client, int fua) {
+        -:  971:	int fhandle;
+        -:  972:	off_t foffset;
+        -:  973:	size_t maxbytes;
+        -:  974:	ssize_t retval;
+        -:  975:
+    75886:  976:	if(get_filepos(client->export, a, &fhandle, &foffset, &maxbytes))
+    #####:  977:		return -1;
+    75886:  978:	if(maxbytes && len > maxbytes)
+    #####:  979:		len = maxbytes;
+        -:  980:
+        -:  981:	DEBUG("(WRITE to fd %d offset %llu len %u fua %d), ", fhandle, (long long unsigned)foffset, (unsigned int)len, fua);
+        -:  982:
+    75886:  983:	myseek(fhandle, foffset);
+    75886:  984:	retval = write(fhandle, buf, len);
+    75886:  985:	if(client->server->flags & F_SYNC) {
+    #####:  986:		fsync(fhandle);
+    75886:  987:	} else if (fua) {
+        -:  988:
+        -:  989:	  /* This is where we would do the following
+        -:  990:	   *   #ifdef USE_SYNC_FILE_RANGE
+        -:  991:	   * However, we don't, for the reasons set out below
+        -:  992:	   * by Christoph Hellwig <hch@infradead.org>
+        -:  993:	   *
+        -:  994:	   * [BEGINS] 
+        -:  995:	   * fdatasync is equivalent to fsync except that it does not flush
+        -:  996:	   * non-essential metadata (basically just timestamps in practice), but it
+        -:  997:	   * does flush metadata requried to find the data again, e.g. allocation
+        -:  998:	   * information and extent maps.  sync_file_range does nothing but flush
+        -:  999:	   * out pagecache content - it means you basically won't get your data
+        -: 1000:	   * back in case of a crash if you either:
+        -: 1001:	   * 
+        -: 1002:	   *  a) have a volatile write cache in your disk (e.g. any normal SATA disk)
+        -: 1003:	   *  b) are using a sparse file on a filesystem
+        -: 1004:	   *  c) are using a fallocate-preallocated file on a filesystem
+        -: 1005:	   *  d) use any file on a COW filesystem like btrfs
+        -: 1006:	   * 
+        -: 1007:	   * e.g. it only does anything useful for you if you do not have a volatile
+        -: 1008:	   * write cache, and either use a raw block device node, or just overwrite
+        -: 1009:	   * an already fully allocated (and not preallocated) file on a non-COW
+        -: 1010:	   * filesystem.
+        -: 1011:	   * [ENDS]
+        -: 1012:	   *
+        -: 1013:	   * What we should do is open a second FD with O_DSYNC set, then write to
+        -: 1014:	   * that when appropriate. However, with a Linux client, every REQ_FUA
+        -: 1015:	   * immediately follows a REQ_FLUSH, so fdatasync does not cause performance
+        -: 1016:	   * problems.
+        -: 1017:	   *
+        -: 1018:	   */
+        -: 1019:#if 0
+        -: 1020:		sync_file_range(fhandle, foffset, len,
+        -: 1021:				SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE |
+        -: 1022:				SYNC_FILE_RANGE_WAIT_AFTER);
+        -: 1023:#else
+     1445: 1024:		fdatasync(fhandle);
+        -: 1025:#endif
+        -: 1026:	}
+    75886: 1027:	return retval;
+        -: 1028:}
+        -: 1029:
+        -: 1030:/**
+        -: 1031: * Call rawexpwrite repeatedly until all data has been written.
+        -: 1032: *
+        -: 1033: * @param a The offset where the write should start
+        -: 1034: * @param buf The buffer to write from
+        -: 1035: * @param len The length of buf
+        -: 1036: * @param client The client we're serving for
+        -: 1037: * @param fua Flag to indicate 'Force Unit Access'
+        -: 1038: * @return 0 on success, nonzero on failure
+        -: 1039: **/
+    75886: 1040:int rawexpwrite_fully(off_t a, char *buf, size_t len, CLIENT *client, int fua) {
+    75886: 1041:	ssize_t ret=0;
+        -: 1042:
+   227658: 1043:	while(len > 0 && (ret=rawexpwrite(a, buf, len, client, fua)) > 0 ) {
+    75886: 1044:		a += ret;
+    75886: 1045:		buf += ret;
+    75886: 1046:		len -= ret;
+        -: 1047:	}
+    75886: 1048:	return (ret < 0 || len != 0);
+        -: 1049:}
+        -: 1050:
+        -: 1051:/**
+        -: 1052: * Read an amount of bytes at a given offset from the right file. This
+        -: 1053: * abstracts the read-side of the multiple files option.
+        -: 1054: *
+        -: 1055: * @param a The offset where the read should start
+        -: 1056: * @param buf A buffer to read into
+        -: 1057: * @param len The size of buf
+        -: 1058: * @param client The client we're serving for
+        -: 1059: * @return The number of bytes actually read, or -1 in case of an
+        -: 1060: * error.
+        -: 1061: **/
+    28783: 1062:ssize_t rawexpread(off_t a, char *buf, size_t len, CLIENT *client) {
+        -: 1063:	int fhandle;
+        -: 1064:	off_t foffset;
+        -: 1065:	size_t maxbytes;
+        -: 1066:
+    28783: 1067:	if(get_filepos(client->export, a, &fhandle, &foffset, &maxbytes))
+    #####: 1068:		return -1;
+    28783: 1069:	if(maxbytes && len > maxbytes)
+    #####: 1070:		len = maxbytes;
+        -: 1071:
+        -: 1072:	DEBUG("(READ from fd %d offset %llu len %u), ", fhandle, (long long unsigned int)foffset, (unsigned int)len);
+        -: 1073:
+    28783: 1074:	myseek(fhandle, foffset);
+    28783: 1075:	return read(fhandle, buf, len);
+        -: 1076:}
+        -: 1077:
+        -: 1078:/**
+        -: 1079: * Call rawexpread repeatedly until all data has been read.
+        -: 1080: * @return 0 on success, nonzero on failure
+        -: 1081: **/
+    28783: 1082:int rawexpread_fully(off_t a, char *buf, size_t len, CLIENT *client) {
+    28783: 1083:	ssize_t ret=0;
+        -: 1084:
+    86349: 1085:	while(len > 0 && (ret=rawexpread(a, buf, len, client)) > 0 ) {
+    28783: 1086:		a += ret;
+    28783: 1087:		buf += ret;
+    28783: 1088:		len -= ret;
+        -: 1089:	}
+    28783: 1090:	return (ret < 0 || len != 0);
+        -: 1091:}
+        -: 1092:
+        -: 1093:/**
+        -: 1094: * Read an amount of bytes at a given offset from the right file. This
+        -: 1095: * abstracts the read-side of the copyonwrite stuff, and calls
+        -: 1096: * rawexpread() with the right parameters to do the actual work.
+        -: 1097: * @param a The offset where the read should start
+        -: 1098: * @param buf A buffer to read into
+        -: 1099: * @param len The size of buf
+        -: 1100: * @param client The client we're going to read for
+        -: 1101: * @return 0 on success, nonzero on failure
+        -: 1102: **/
+    28783: 1103:int expread(off_t a, char *buf, size_t len, CLIENT *client) {
+        -: 1104:	off_t rdlen, offset;
+        -: 1105:	off_t mapcnt, mapl, maph, pagestart;
+        -: 1106:
+    28783: 1107:	if (!(client->server->flags & F_COPYONWRITE))
+    24687: 1108:		return(rawexpread_fully(a, buf, len, client));
+        -: 1109:	DEBUG("Asked to read %u bytes at %llu.\n", (unsigned int)len, (unsigned long long)a);
+        -: 1110:
+     4096: 1111:	mapl=a/DIFFPAGESIZE; maph=(a+len-1)/DIFFPAGESIZE;
+        -: 1112:
+     8192: 1113:	for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
+     4096: 1114:		pagestart=mapcnt*DIFFPAGESIZE;
+     4096: 1115:		offset=a-pagestart;
+     5120: 1116:		rdlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
+     1024: 1117:			len : (size_t)DIFFPAGESIZE-offset;
+     4096: 1118:		if (client->difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
+        -: 1119:			DEBUG("Page %llu is at %lu\n", (unsigned long long)mapcnt,
+        -: 1120:			       (unsigned long)(client->difmap[mapcnt]));
+    #####: 1121:			myseek(client->difffile, client->difmap[mapcnt]*DIFFPAGESIZE+offset);
+    #####: 1122:			if (read(client->difffile, buf, rdlen) != rdlen) return -1;
+        -: 1123:		} else { /* the block is not there */
+        -: 1124:			DEBUG("Page %llu is not here, we read the original one\n",
+        -: 1125:			       (unsigned long long)mapcnt);
+     4096: 1126:			if(rawexpread_fully(a, buf, rdlen, client)) return -1;
+        -: 1127:		}
+     4096: 1128:		len-=rdlen; a+=rdlen; buf+=rdlen;
+        -: 1129:	}
+     4096: 1130:	return 0;
+        -: 1131:}
+        -: 1132:
+        -: 1133:/**
+        -: 1134: * Write an amount of bytes at a given offset to the right file. This
+        -: 1135: * abstracts the write-side of the copyonwrite option, and calls
+        -: 1136: * rawexpwrite() with the right parameters to do the actual work.
+        -: 1137: *
+        -: 1138: * @param a The offset where the write should start
+        -: 1139: * @param buf The buffer to write from
+        -: 1140: * @param len The length of buf
+        -: 1141: * @param client The client we're going to write for.
+        -: 1142: * @param fua Flag to indicate 'Force Unit Access'
+        -: 1143: * @return 0 on success, nonzero on failure
+        -: 1144: **/
+    75886: 1145:int expwrite(off_t a, char *buf, size_t len, CLIENT *client, int fua) {
+        -: 1146:	char pagebuf[DIFFPAGESIZE];
+        -: 1147:	off_t mapcnt,mapl,maph;
+        -: 1148:	off_t wrlen,rdlen; 
+        -: 1149:	off_t pagestart;
+        -: 1150:	off_t offset;
+        -: 1151:
+    75886: 1152:	if (!(client->server->flags & F_COPYONWRITE))
+    75886: 1153:		return(rawexpwrite_fully(a, buf, len, client, fua)); 
+        -: 1154:	DEBUG("Asked to write %u bytes at %llu.\n", (unsigned int)len, (unsigned long long)a);
+        -: 1155:
+    #####: 1156:	mapl=a/DIFFPAGESIZE ; maph=(a+len-1)/DIFFPAGESIZE ;
+        -: 1157:
+    #####: 1158:	for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
+    #####: 1159:		pagestart=mapcnt*DIFFPAGESIZE ;
+    #####: 1160:		offset=a-pagestart ;
+    #####: 1161:		wrlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
+    #####: 1162:			len : (size_t)DIFFPAGESIZE-offset;
+        -: 1163:
+    #####: 1164:		if (client->difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
+        -: 1165:			DEBUG("Page %llu is at %lu\n", (unsigned long long)mapcnt,
+        -: 1166:			       (unsigned long)(client->difmap[mapcnt])) ;
+    #####: 1167:			myseek(client->difffile,
+    #####: 1168:					client->difmap[mapcnt]*DIFFPAGESIZE+offset);
+    #####: 1169:			if (write(client->difffile, buf, wrlen) != wrlen) return -1 ;
+        -: 1170:		} else { /* the block is not there */
+    #####: 1171:			myseek(client->difffile,client->difffilelen*DIFFPAGESIZE) ;
+    #####: 1172:			client->difmap[mapcnt]=(client->server->flags&F_SPARSE)?mapcnt:client->difffilelen++;
+        -: 1173:			DEBUG("Page %llu is not here, we put it at %lu\n",
+        -: 1174:			       (unsigned long long)mapcnt,
+        -: 1175:			       (unsigned long)(client->difmap[mapcnt]));
+    #####: 1176:			rdlen=DIFFPAGESIZE ;
+    #####: 1177:			if (rawexpread_fully(pagestart, pagebuf, rdlen, client))
+    #####: 1178:				return -1;
+    #####: 1179:			memcpy(pagebuf+offset,buf,wrlen) ;
+    #####: 1180:			if (write(client->difffile, pagebuf, DIFFPAGESIZE) !=
+        -: 1181:					DIFFPAGESIZE)
+    #####: 1182:				return -1;
+        -: 1183:		}						    
+    #####: 1184:		len-=wrlen ; a+=wrlen ; buf+=wrlen ;
+        -: 1185:	}
+    #####: 1186:	if (client->server->flags & F_SYNC) {
+    #####: 1187:		fsync(client->difffile);
+    #####: 1188:	} else if (fua) {
+        -: 1189:		/* open question: would it be cheaper to do multiple sync_file_ranges?
+        -: 1190:		   as we iterate through the above?
+        -: 1191:		 */
+    #####: 1192:		fdatasync(client->difffile);
+        -: 1193:	}
+    #####: 1194:	return 0;
+        -: 1195:}
+        -: 1196:
+        -: 1197:/**
+        -: 1198: * Flush data to a client
+        -: 1199: *
+        -: 1200: * @param client The client we're going to write for.
+        -: 1201: * @return 0 on success, nonzero on failure
+        -: 1202: **/
+     1447: 1203:int expflush(CLIENT *client) {
+        -: 1204:	gint i;
+        -: 1205:
+     1447: 1206:        if (client->server->flags & F_COPYONWRITE) {
+    #####: 1207:		return fsync(client->difffile);
+        -: 1208:	}
+        -: 1209:	
+     2894: 1210:	for (i = 0; i < client->export->len; i++) {
+     1447: 1211:		FILE_INFO fi = g_array_index(client->export, FILE_INFO, i);
+     1447: 1212:		if (fsync(fi.fhandle) < 0)
+    #####: 1213:			return -1;
+        -: 1214:	}
+        -: 1215:	
+     1447: 1216:	return 0;
+        -: 1217:}
+        -: 1218:
+        -: 1219:/*
+        -: 1220: * If the current system supports it, call fallocate() on the backend
+        -: 1221: * file to resparsify stuff that isn't needed anymore (see NBD_CMD_TRIM)
+        -: 1222: */
+    #####: 1223:int exptrim(struct nbd_request* req, CLIENT* client) {
+        -: 1224:#if HAVE_FALLOC_PH
+    #####: 1225:	FILE_INFO prev = g_array_index(client->export, FILE_INFO, 0);
+    #####: 1226:	FILE_INFO cur = prev;
+    #####: 1227:	int i = 1;
+        -: 1228:	/* We're running on a system that supports the
+        -: 1229:	 * FALLOC_FL_PUNCH_HOLE option to re-sparsify a file */
+        -: 1230:	do {
+    #####: 1231:		if(i<client->export->len) {
+    #####: 1232:			cur = g_array_index(client->export, FILE_INFO, i);
+        -: 1233:		}
+    #####: 1234:		if(prev.startoff <= req->from) {
+    #####: 1235:			off_t curoff = req->from - prev.startoff;
+    #####: 1236:			off_t curlen = cur.startoff - prev.startoff - curoff;
+    #####: 1237:			fallocate(prev.fhandle, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, curoff, curlen);
+        -: 1238:		}
+    #####: 1239:		prev = cur;
+    #####: 1240:	} while(i < client->export->len && cur.startoff < (req->from + req->len));
+        -: 1241:	DEBUG("Performed TRIM request from %llu to %llu", (unsigned long long) req->from, (unsigned long long) req->len);
+        -: 1242:#else
+        -: 1243:	DEBUG("Ignoring TRIM request (not supported on current platform");
+        -: 1244:#endif
+    #####: 1245:	return 0;
+        -: 1246:}
+        -: 1247:
+        2: 1248:static void send_reply(uint32_t opt, int net, uint32_t reply_type, size_t datasize, void* data) {
+        2: 1249:	uint64_t magic = htonll(0x3e889045565a9LL);
+        2: 1250:	reply_type = htonl(reply_type);
+        2: 1251:	uint32_t datsize = htonl(datasize);
+        2: 1252:	opt = htonl(opt);
+        2: 1253:	struct iovec v_data[] = {
+        -: 1254:		{ &magic, sizeof(magic) },
+        -: 1255:		{ &opt, sizeof(opt) },
+        -: 1256:		{ &reply_type, sizeof(reply_type) },
+        -: 1257:		{ &datsize, sizeof(datsize) },
+        -: 1258:		{ data, datasize },
+        -: 1259:	};
+        2: 1260:	size_t total = sizeof(magic) + sizeof(opt) + sizeof(reply_type) + sizeof(datsize) + datasize;
+        2: 1261:	ssize_t sent = writev(net, v_data, 5);
+        2: 1262:	if(sent != total) {
+    #####: 1263:		perror("E: couldn't write enough data:");
+        -: 1264:	}
+        2: 1265:}
+        -: 1266:
+        6: 1267:static CLIENT* handle_export_name(uint32_t opt, int net, GArray* servers, uint32_t cflags) {
+        -: 1268:	uint32_t namelen;
+        -: 1269:	char* name;
+        -: 1270:	int i;
+        -: 1271:
+        6: 1272:	if (read(net, &namelen, sizeof(namelen)) < 0) {
+    #####: 1273:		err("Negotiation failed/7: %m");
+        -: 1274:		return NULL;
+        -: 1275:	}
+        6: 1276:	namelen = ntohl(namelen);
+        6: 1277:	name = malloc(namelen+1);
+        6: 1278:	name[namelen]=0;
+        6: 1279:	if (read(net, name, namelen) < 0) {
+    #####: 1280:		err("Negotiation failed/8: %m");
+        -: 1281:		free(name);
+        -: 1282:		return NULL;
+        -: 1283:	}
+        6: 1284:	for(i=0; i<servers->len; i++) {
+        6: 1285:		SERVER* serve = &(g_array_index(servers, SERVER, i));
+        6: 1286:		if(!strcmp(serve->servename, name)) {
+        6: 1287:			CLIENT* client = g_new0(CLIENT, 1);
+        6: 1288:			client->server = serve;
+        6: 1289:			client->exportsize = OFFT_MAX;
+        6: 1290:			client->net = net;
+        6: 1291:			client->modern = TRUE;
+        6: 1292:			client->transactionlogfd = -1;
+        6: 1293:			client->clientfeats = cflags;
+        6: 1294:			free(name);
+        6: 1295:			return client;
+        -: 1296:		}
+        -: 1297:	}
+    #####: 1298:	err("Negotiation failed/8a: Requested export not found");
+        -: 1299:	free(name);
+        -: 1300:	return NULL;
+        -: 1301:}
+        -: 1302:
+        1: 1303:static void handle_list(uint32_t opt, int net, GArray* servers, uint32_t cflags) {
+        -: 1304:	uint32_t len;
+        -: 1305:	int i;
+        -: 1306:	char buf[1024];
+        1: 1307:	char *ptr = buf + sizeof(len);
+        -: 1308:
+        1: 1309:	if (read(net, &len, sizeof(len)) < 0)
+    #####: 1310:		err("Negotiation failed/8: %m");
+        1: 1311:	len = ntohl(len);
+        1: 1312:	if(len) {
+    #####: 1313:		send_reply(opt, net, NBD_REP_ERR_INVALID, 0, NULL);
+        -: 1314:	}
+        1: 1315:	if(!(glob_flags & F_LIST)) {
+    #####: 1316:		send_reply(opt, net, NBD_REP_ERR_POLICY, 0, NULL);
+    #####: 1317:		err_nonfatal("Client tried disallowed list option");
+        1: 1318:		return;
+        -: 1319:	}
+        2: 1320:	for(i=0; i<servers->len; i++) {
+        1: 1321:		SERVER* serve = &(g_array_index(servers, SERVER, i));
+        1: 1322:		len = htonl(strlen(serve->servename));
+        1: 1323:		memcpy(buf, &len, sizeof(len));
+        1: 1324:		strcpy(ptr, serve->servename);
+        1: 1325:		send_reply(opt, net, NBD_REP_SERVER, strlen(serve->servename)+sizeof(len), buf);
+        -: 1326:	}
+        1: 1327:	send_reply(opt, net, NBD_REP_ACK, 0, NULL);
+        -: 1328:}
+        -: 1329:
+        -: 1330:/**
+        -: 1331: * Do the initial negotiation.
+        -: 1332: *
+        -: 1333: * @param client The client we're negotiating with.
+        -: 1334: **/
+       18: 1335:CLIENT* negotiate(int net, CLIENT *client, GArray* servers, int phase) {
+        -: 1336:	char zeros[128];
+        -: 1337:	uint64_t size_host;
+       18: 1338:	uint32_t flags = NBD_FLAG_HAS_FLAGS;
+       18: 1339:	uint16_t smallflags = 0;
+        -: 1340:	uint64_t magic;
+        -: 1341:
+       18: 1342:	memset(zeros, '\0', sizeof(zeros));
+       18: 1343:	assert(((phase & NEG_INIT) && (phase & NEG_MODERN)) || client);
+       18: 1344:	if(phase & NEG_MODERN) {
+       13: 1345:		smallflags |= NBD_FLAG_FIXED_NEWSTYLE;
+        -: 1346:	}
+       18: 1347:	if(phase & NEG_INIT) {
+        -: 1348:		/* common */
+       12: 1349:		if (write(net, INIT_PASSWD, 8) < 0) {
+    #####: 1350:			err_nonfatal("Negotiation failed/1: %m");
+    #####: 1351:			if(client)
+    #####: 1352:				exit(EXIT_FAILURE);
+        -: 1353:		}
+       12: 1354:		if(phase & NEG_MODERN) {
+        -: 1355:			/* modern */
+        7: 1356:			magic = htonll(opts_magic);
+        -: 1357:		} else {
+        -: 1358:			/* oldstyle */
+        5: 1359:			magic = htonll(cliserv_magic);
+        -: 1360:		}
+       12: 1361:		if (write(net, &magic, sizeof(magic)) < 0) {
+    #####: 1362:			err_nonfatal("Negotiation failed/2: %m");
+    #####: 1363:			if(phase & NEG_OLD)
+    #####: 1364:				exit(EXIT_FAILURE);
+        -: 1365:		}
+        -: 1366:	}
+       18: 1367:	if ((phase & NEG_MODERN) && (phase & NEG_INIT)) {
+        -: 1368:		/* modern */
+        -: 1369:		uint32_t cflags;
+        -: 1370:		uint32_t opt;
+        -: 1371:
+        7: 1372:		if(!servers)
+    #####: 1373:			err("programmer error");
+        7: 1374:		smallflags = htons(smallflags);
+        7: 1375:		if (write(net, &smallflags, sizeof(uint16_t)) < 0)
+    #####: 1376:			err_nonfatal("Negotiation failed/3: %m");
+        7: 1377:		if (read(net, &cflags, sizeof(cflags)) < 0)
+    #####: 1378:			err_nonfatal("Negotiation failed/4: %m");
+        7: 1379:		cflags = htonl(cflags);
+        -: 1380:		do {
+        8: 1381:			if (read(net, &magic, sizeof(magic)) < 0)
+    #####: 1382:				err_nonfatal("Negotiation failed/5: %m");
+        8: 1383:			magic = ntohll(magic);
+        8: 1384:			if(magic != opts_magic) {
+    #####: 1385:				err_nonfatal("Negotiation failed/5a: magic mismatch");
+        7: 1386:				return NULL;
+        -: 1387:			}
+        8: 1388:			if (read(net, &opt, sizeof(opt)) < 0)
+    #####: 1389:				err_nonfatal("Negotiation failed/6: %m");
+        8: 1390:			opt = ntohl(opt);
+        8: 1391:			switch(opt) {
+        -: 1392:			case NBD_OPT_EXPORT_NAME:
+        -: 1393:				// NBD_OPT_EXPORT_NAME must be the last
+        -: 1394:				// selected option, so return from here
+        -: 1395:				// if that is chosen.
+        6: 1396:				return handle_export_name(opt, net, servers, cflags);
+        -: 1397:				break;
+        -: 1398:			case NBD_OPT_LIST:
+        1: 1399:				handle_list(opt, net, servers, cflags);
+        1: 1400:				break;
+        -: 1401:			case NBD_OPT_ABORT:
+        -: 1402:				// handled below
+        1: 1403:				break;
+        -: 1404:			default:
+    #####: 1405:				send_reply(opt, net, NBD_REP_ERR_UNSUP, 0, NULL);
+    #####: 1406:				break;
+        -: 1407:			}
+        2: 1408:		} while((opt != NBD_OPT_EXPORT_NAME) && (opt != NBD_OPT_ABORT));
+        1: 1409:		if(opt == NBD_OPT_ABORT) {
+        1: 1410:			err_nonfatal("Session terminated by client");
+        1: 1411:			return NULL;
+        -: 1412:		}
+        -: 1413:	}
+        -: 1414:	/* common */
+       11: 1415:	size_host = htonll((u64)(client->exportsize));
+       11: 1416:	if (write(net, &size_host, 8) < 0)
+    #####: 1417:		err("Negotiation failed/9: %m");
+       11: 1418:	if (client->server->flags & F_READONLY)
+        2: 1419:		flags |= NBD_FLAG_READ_ONLY;
+       11: 1420:	if (client->server->flags & F_FLUSH)
+        2: 1421:		flags |= NBD_FLAG_SEND_FLUSH;
+       11: 1422:	if (client->server->flags & F_FUA)
+        2: 1423:		flags |= NBD_FLAG_SEND_FUA;
+       11: 1424:	if (client->server->flags & F_ROTATIONAL)
+        2: 1425:		flags |= NBD_FLAG_ROTATIONAL;
+       11: 1426:	if (client->server->flags & F_TRIM)
+    #####: 1427:		flags |= NBD_FLAG_SEND_TRIM;
+       11: 1428:	if (phase & NEG_OLD) {
+        -: 1429:		/* oldstyle */
+        5: 1430:		flags = htonl(flags);
+        5: 1431:		if (write(client->net, &flags, 4) < 0)
+    #####: 1432:			err("Negotiation failed/10: %m");
+        -: 1433:	} else {
+        -: 1434:		/* modern */
+        6: 1435:		smallflags = (uint16_t)(flags & ~((uint16_t)0));
+        6: 1436:		smallflags = htons(smallflags);
+        6: 1437:		if (write(client->net, &smallflags, sizeof(smallflags)) < 0) {
+    #####: 1438:			err("Negotiation failed/11: %m");
+        -: 1439:		}
+        -: 1440:	}
+        -: 1441:	/* common */
+       11: 1442:	if (write(client->net, zeros, 124) < 0)
+    #####: 1443:		err("Negotiation failed/12: %m");
+       11: 1444:	return NULL;
+        -: 1445:}
+        -: 1446:
+        -: 1447:/** sending macro. */
+        -: 1448:#define SEND(net,reply) { writeit( net, &reply, sizeof( reply )); \
+        -: 1449:	if (client->transactionlogfd != -1) \
+        -: 1450:		writeit(client->transactionlogfd, &reply, sizeof(reply)); }
+        -: 1451:/** error macro. */
+        -: 1452:#define ERROR(client,reply,errcode) { reply.error = htonl(errcode); SEND(client->net,reply); reply.error = 0; }
+        -: 1453:/**
+        -: 1454: * Serve a file to a single client.
+        -: 1455: *
+        -: 1456: * @todo This beast needs to be split up in many tiny little manageable
+        -: 1457: * pieces. Preferably with a chainsaw.
+        -: 1458: *
+        -: 1459: * @param client The client we're going to serve to.
+        -: 1460: * @return when the client disconnects
+        -: 1461: **/
+       11: 1462:int mainloop(CLIENT *client) {
+        -: 1463:	struct nbd_request request;
+        -: 1464:	struct nbd_reply reply;
+       11: 1465:	gboolean go_on=TRUE;
+        -: 1466:#ifdef DODBG
+        -: 1467:	int i = 0;
+        -: 1468:#endif
+       11: 1469:	negotiate(client->net, client, NULL, client->modern ? NEG_MODERN : (NEG_OLD | NEG_INIT));
+        -: 1470:	DEBUG("Entering request loop!\n");
+       11: 1471:	reply.magic = htonl(NBD_REPLY_MAGIC);
+       11: 1472:	reply.error = 0;
+   106145: 1473:	while (go_on) {
+        -: 1474:		char buf[BUFSIZE];
+        -: 1475:		char* p;
+        -: 1476:		size_t len;
+        -: 1477:		size_t currlen;
+        -: 1478:		size_t writelen;
+        -: 1479:		uint16_t command;
+        -: 1480:#ifdef DODBG
+        -: 1481:		i++;
+        -: 1482:		printf("%d: ", i);
+        -: 1483:#endif
+   106124: 1484:		readit(client->net, &request, sizeof(request));
+   106123: 1485:		if (client->transactionlogfd != -1)
+    #####: 1486:			writeit(client->transactionlogfd, &request, sizeof(request));
+        -: 1487:
+   106123: 1488:		request.from = ntohll(request.from);
+   106123: 1489:		request.type = ntohl(request.type);
+   106123: 1490:		command = request.type & NBD_CMD_MASK_COMMAND;
+   106123: 1491:		len = ntohl(request.len);
+        -: 1492:
+        -: 1493:		DEBUG("%s from %llu (%llu) len %u, ", getcommandname(command),
+        -: 1494:				(unsigned long long)request.from,
+        -: 1495:				(unsigned long long)request.from / 512, len);
+        -: 1496:
+   106123: 1497:		if (request.magic != htonl(NBD_REQUEST_MAGIC))
+    #####: 1498:			err("Not enough magic.");
+        -: 1499:
+   106123: 1500:		memcpy(reply.handle, request.handle, sizeof(reply.handle));
+        -: 1501:
+   106123: 1502:		if ((command==NBD_CMD_WRITE) || (command==NBD_CMD_READ)) {
+   104666: 1503:			if (request.from + len < request.from) { // 64 bit overflow!!
+        -: 1504:				DEBUG("[Number too large!]");
+    #####: 1505:				ERROR(client, reply, EINVAL);
+    #####: 1506:				continue;
+        -: 1507:			}
+        -: 1508:
+   104666: 1509:			if (((off_t)request.from + len) > client->exportsize) {
+        -: 1510:				DEBUG("[RANGE!]");
+    #####: 1511:				ERROR(client, reply, EINVAL);
+    #####: 1512:				continue;
+        -: 1513:			}
+        -: 1514:
+   104666: 1515:			currlen = len;
+   104666: 1516:			if (currlen > BUFSIZE - sizeof(struct nbd_reply)) {
+        2: 1517:				currlen = BUFSIZE - sizeof(struct nbd_reply);
+        2: 1518:				if(!logged_oversized) {
+        1: 1519:					msg(LOG_DEBUG, "oversized request (this is not a problem)");
+        1: 1520:					logged_oversized = true;
+        -: 1521:				}
+        -: 1522:			}
+        -: 1523:		}
+        -: 1524:
+   106123: 1525:		switch (command) {
+        -: 1526:
+        -: 1527:		case NBD_CMD_DISC:
+       10: 1528:			msg(LOG_INFO, "Disconnect request received.");
+       10: 1529:                	if (client->server->flags & F_COPYONWRITE) { 
+        1: 1530:				if (client->difmap) g_free(client->difmap) ;
+        1: 1531:                		close(client->difffile);
+        1: 1532:				unlink(client->difffilename);
+        1: 1533:				free(client->difffilename);
+        -: 1534:			}
+       10: 1535:			go_on=FALSE;
+       10: 1536:			continue;
+        -: 1537:
+        -: 1538:		case NBD_CMD_WRITE:
+        -: 1539:			DEBUG("wr: net->buf, ");
+   227658: 1540:			while(len > 0) {
+    75886: 1541:				readit(client->net, buf, currlen);
+        -: 1542:				DEBUG("buf->exp, ");
+   151772: 1543:				if ((client->server->flags & F_READONLY) ||
+    75886: 1544:				    (client->server->flags & F_AUTOREADONLY)) {
+        -: 1545:					DEBUG("[WRITE to READONLY!]");
+    #####: 1546:					ERROR(client, reply, EPERM);
+    #####: 1547:					consume(client->net, buf, len-currlen, BUFSIZE);
+    #####: 1548:					continue;
+        -: 1549:				}
+    75886: 1550:				if (expwrite(request.from, buf, currlen, client,
+    75886: 1551:					     request.type & NBD_CMD_FLAG_FUA)) {
+        -: 1552:					DEBUG("Write failed: %m" );
+    #####: 1553:					ERROR(client, reply, errno);
+    #####: 1554:					consume(client->net, buf, len-currlen, BUFSIZE);
+    #####: 1555:					continue;
+        -: 1556:				}
+    75886: 1557:				len -= currlen;
+    75886: 1558:				request.from += currlen;
+    75886: 1559:				currlen = (len < BUFSIZE) ? len : BUFSIZE;
+        -: 1560:			}
+    75886: 1561:			SEND(client->net, reply);
+        -: 1562:			DEBUG("OK!\n");
+    75886: 1563:			continue;
+        -: 1564:
+        -: 1565:		case NBD_CMD_FLUSH:
+        -: 1566:			DEBUG("fl: ");
+     1447: 1567:			if (expflush(client)) {
+        -: 1568:				DEBUG("Flush failed: %m");
+    #####: 1569:				ERROR(client, reply, errno);
+    #####: 1570:				continue;
+        -: 1571:			}
+     1447: 1572:			SEND(client->net, reply);
+        -: 1573:			DEBUG("OK!\n");
+     1447: 1574:			continue;
+        -: 1575:
+        -: 1576:		case NBD_CMD_READ:
+        -: 1577:			DEBUG("exp->buf, ");
+    28780: 1578:			if (client->transactionlogfd != -1)
+    #####: 1579:				writeit(client->transactionlogfd, &reply, sizeof(reply));
+    28780: 1580:			writeit(client->net, &reply, sizeof(reply));
+    28780: 1581:			p = buf;
+    28780: 1582:			writelen = currlen;
+    86343: 1583:			while(len > 0) {
+    28783: 1584:				if (expread(request.from, p, currlen, client)) {
+        -: 1585:					DEBUG("Read failed: %m");
+    #####: 1586:					ERROR(client, reply, errno);
+    #####: 1587:					continue;
+        -: 1588:				}
+        -: 1589:				
+        -: 1590:				DEBUG("buf->net, ");
+    28783: 1591:				writeit(client->net, buf, writelen);
+    28783: 1592:				len -= currlen;
+    28783: 1593:				request.from += currlen;
+    28783: 1594:				currlen = (len < BUFSIZE) ? len : BUFSIZE;
+    28783: 1595:				p = buf;
+    28783: 1596:				writelen = currlen;
+        -: 1597:			}
+        -: 1598:			DEBUG("OK!\n");
+    28780: 1599:			continue;
+        -: 1600:
+        -: 1601:		case NBD_CMD_TRIM:
+        -: 1602:			/* The kernel module sets discard_zeroes_data == 0,
+        -: 1603:			 * so it is okay to do nothing.  */
+    #####: 1604:			if (exptrim(&request, client)) {
+        -: 1605:				DEBUG("Trim failed: %m");
+    #####: 1606:				ERROR(client, reply, errno);
+    #####: 1607:				continue;
+        -: 1608:			}
+    #####: 1609:			SEND(client->net, reply);
+    #####: 1610:			continue;
+        -: 1611:
+        -: 1612:		default:
+        -: 1613:			DEBUG ("Ignoring unknown command\n");
+    #####: 1614:			continue;
+        -: 1615:		}
+        -: 1616:	}
+       10: 1617:	return 0;
+        -: 1618:}
+        -: 1619:
+        -: 1620:/**
+        -: 1621: * Set up client export array, which is an array of FILE_INFO.
+        -: 1622: * Also, split a single exportfile into multiple ones, if that was asked.
+        -: 1623: * @param client information on the client which we want to setup export for
+        -: 1624: **/
+       11: 1625:void setupexport(CLIENT* client) {
+        -: 1626:	int i;
+       11: 1627:	off_t laststartoff = 0, lastsize = 0;
+       11: 1628:	int multifile = (client->server->flags & F_MULTIFILE);
+       11: 1629:	int temporary = (client->server->flags & F_TEMPORARY) && !multifile;
+       11: 1630:	int cancreate = (client->server->expected_size) && !multifile;
+        -: 1631:
+       11: 1632:	client->export = g_array_new(TRUE, TRUE, sizeof(FILE_INFO));
+        -: 1633:
+        -: 1634:	/* If multi-file, open as many files as we can.
+        -: 1635:	 * If not, open exactly one file.
+        -: 1636:	 * Calculate file sizes as we go to get total size. */
+       11: 1637:	for(i=0; ; i++) {
+        -: 1638:		FILE_INFO fi;
+        -: 1639:		gchar *tmpname;
+        -: 1640:		gchar* error_string;
+        -: 1641:
+       11: 1642:		if (i)
+    #####: 1643:		  cancreate = 0;
+        -: 1644:		/* if expected_size is specified, and this is the first file, we can create the file */
+       11: 1645:		mode_t mode = (client->server->flags & F_READONLY) ?
+        -: 1646:		  O_RDONLY : (O_RDWR | (cancreate?O_CREAT:0));
+        -: 1647:
+       11: 1648:		if (temporary) {
+        1: 1649:			tmpname=g_strdup_printf("%s.%d-XXXXXX", client->exportname, i);
+        -: 1650:			DEBUG( "Opening %s\n", tmpname );
+        1: 1651:			fi.fhandle = mkstemp(tmpname);
+        -: 1652:		} else {
+       10: 1653:			if(multifile) {
+    #####: 1654:				tmpname=g_strdup_printf("%s.%d", client->exportname, i);
+        -: 1655:			} else {
+       10: 1656:				tmpname=g_strdup(client->exportname);
+        -: 1657:			}
+        -: 1658:			DEBUG( "Opening %s\n", tmpname );
+       10: 1659:			fi.fhandle = open(tmpname, mode, 0x600);
+       10: 1660:			if(fi.fhandle == -1 && mode == O_RDWR) {
+        -: 1661:				/* Try again because maybe media was read-only */
+    #####: 1662:				fi.fhandle = open(tmpname, O_RDONLY);
+    #####: 1663:				if(fi.fhandle != -1) {
+        -: 1664:					/* Opening the base file in copyonwrite mode is
+        -: 1665:					 * okay */
+    #####: 1666:					if(!(client->server->flags & F_COPYONWRITE)) {
+    #####: 1667:						client->server->flags |= F_AUTOREADONLY;
+    #####: 1668:						client->server->flags |= F_READONLY;
+        -: 1669:					}
+        -: 1670:				}
+        -: 1671:			}
+        -: 1672:		}
+       11: 1673:		if(fi.fhandle == -1) {
+    #####: 1674:			if(multifile && i>0)
+       11: 1675:				break;
+    #####: 1676:			error_string=g_strdup_printf(
+        -: 1677:				"Could not open exported file %s: %%m",
+        -: 1678:				tmpname);
+    #####: 1679:			err(error_string);
+        -: 1680:		}
+        -: 1681:
+       11: 1682:		if (temporary)
+        1: 1683:			unlink(tmpname); /* File will stick around whilst FD open */
+        -: 1684:
+       11: 1685:		fi.startoff = laststartoff + lastsize;
+       11: 1686:		g_array_append_val(client->export, fi);
+       11: 1687:		g_free(tmpname);
+        -: 1688:
+        -: 1689:		/* Starting offset and size of this file will be used to
+        -: 1690:		 * calculate starting offset of next file */
+       11: 1691:		laststartoff = fi.startoff;
+       11: 1692:		lastsize = size_autodetect(fi.fhandle);
+        -: 1693:
+        -: 1694:		/* If we created the file, it will be length zero */
+       11: 1695:		if (!lastsize && cancreate) {
+        1: 1696:			assert(!multifile);
+        1: 1697:			if(ftruncate (fi.fhandle, client->server->expected_size)<0) {
+    #####: 1698:				err("Could not expand file: %m");
+        -: 1699:			}
+        1: 1700:			lastsize = client->server->expected_size;
+        1: 1701:			break; /* don't look for any more files */
+        -: 1702:		}
+        -: 1703:
+       10: 1704:		if(!multifile || temporary)
+        -: 1705:			break;
+    #####: 1706:	}
+        -: 1707:
+        -: 1708:	/* Set export size to total calculated size */
+       11: 1709:	client->exportsize = laststartoff + lastsize;
+        -: 1710:
+        -: 1711:	/* Export size may be overridden */
+       11: 1712:	if(client->server->expected_size) {
+        -: 1713:		/* desired size must be <= total calculated size */
+        1: 1714:		if(client->server->expected_size > client->exportsize) {
+    #####: 1715:			err("Size of exported file is too big\n");
+        -: 1716:		}
+        -: 1717:
+        1: 1718:		client->exportsize = client->server->expected_size;
+        -: 1719:	}
+        -: 1720:
+       11: 1721:	msg(LOG_INFO, "Size of exported file/device is %llu", (unsigned long long)client->exportsize);
+       11: 1722:	if(multifile) {
+    #####: 1723:		msg(LOG_INFO, "Total number of files: %d", i);
+        -: 1724:	}
+       11: 1725:}
+        -: 1726:
+        1: 1727:int copyonwrite_prepare(CLIENT* client) {
+        -: 1728:	off_t i;
+        -: 1729:	gchar* dir;
+        -: 1730:	gchar* export_base;
+        1: 1731:	if (client->server->cowdir != NULL) {
+    #####: 1732:		dir = g_strdup(client->server->cowdir);
+        -: 1733:	} else {
+        1: 1734:		dir = g_strdup(dirname(client->exportname));
+        -: 1735:	}
+        1: 1736:	export_base = g_strdup(basename(client->exportname));
+        1: 1737:	client->difffilename = g_strdup_printf("%s/%s-%s-%d.diff",dir,export_base,client->clientname,
+        -: 1738:		(int)getpid());
+        1: 1739:	g_free(dir);
+        1: 1740:	g_free(export_base);
+        1: 1741:	msg(LOG_INFO, "About to create map and diff file %s", client->difffilename) ;
+        1: 1742:	client->difffile=open(client->difffilename,O_RDWR | O_CREAT | O_TRUNC,0600) ;
+        1: 1743:	if (client->difffile<0) err("Could not create diff file (%m)") ;
+        1: 1744:	if ((client->difmap=calloc(client->exportsize/DIFFPAGESIZE,sizeof(u32)))==NULL)
+    #####: 1745:		err("Could not allocate memory") ;
+        1: 1746:	for (i=0;i<client->exportsize/DIFFPAGESIZE;i++) client->difmap[i]=(u32)-1 ;
+        -: 1747:
+        1: 1748:	return 0;
+        -: 1749:}
+        -: 1750:
+        -: 1751:/**
+        -: 1752: * Run a command. This is used for the ``prerun'' and ``postrun'' config file
+        -: 1753: * options
+        -: 1754: *
+        -: 1755: * @param command the command to be ran. Read from the config file
+        -: 1756: * @param file the file name we're about to export
+        -: 1757: **/
+       21: 1758:int do_run(gchar* command, gchar* file) {
+        -: 1759:	gchar* cmd;
+       21: 1760:	int retval=0;
+        -: 1761:
+       21: 1762:	if(command && *command) {
+    #####: 1763:		cmd = g_strdup_printf(command, file);
+    #####: 1764:		retval=system(cmd);
+    #####: 1765:		g_free(cmd);
+        -: 1766:	}
+       21: 1767:	return retval;
+        -: 1768:}
+        -: 1769:
+        -: 1770:/**
+        -: 1771: * Serve a connection. 
+        -: 1772: *
+        -: 1773: * @todo allow for multithreading, perhaps use libevent. Not just yet, though;
+        -: 1774: * follow the road map.
+        -: 1775: *
+        -: 1776: * @param client a connected client
+        -: 1777: **/
+       11: 1778:void serveconnection(CLIENT *client) {
+       11: 1779:	if (client->server->transactionlog && (client->transactionlogfd == -1))
+        -: 1780:	{
+    #####: 1781:		if (-1 == (client->transactionlogfd = open(client->server->transactionlog,
+        -: 1782:							   O_WRONLY | O_CREAT,
+        -: 1783:							   S_IRUSR | S_IWUSR)))
+    #####: 1784:			g_warning("Could not open transaction log %s",
+        -: 1785:				  client->server->transactionlog);
+        -: 1786:	}
+        -: 1787:
+       11: 1788:	if(do_run(client->server->prerun, client->exportname)) {
+    #####: 1789:		exit(EXIT_FAILURE);
+        -: 1790:	}
+       11: 1791:	setupexport(client);
+        -: 1792:
+       11: 1793:	if (client->server->flags & F_COPYONWRITE) {
+        1: 1794:		copyonwrite_prepare(client);
+        -: 1795:	}
+        -: 1796:
+       11: 1797:	setmysockopt(client->net);
+        -: 1798:
+       11: 1799:	mainloop(client);
+       10: 1800:	do_run(client->server->postrun, client->exportname);
+        -: 1801:
+       10: 1802:	if (-1 != client->transactionlogfd)
+        -: 1803:	{
+    #####: 1804:		close(client->transactionlogfd);
+    #####: 1805:		client->transactionlogfd = -1;
+        -: 1806:	}
+       10: 1807:}
+        -: 1808:
+        -: 1809:/**
+        -: 1810: * Find the name of the file we have to serve. This will use g_strdup_printf
+        -: 1811: * to put the IP address of the client inside a filename containing
+        -: 1812: * "%s" (in the form as specified by the "virtstyle" option). That name
+        -: 1813: * is then written to client->exportname.
+        -: 1814: *
+        -: 1815: * @param net A socket connected to an nbd client
+        -: 1816: * @param client information about the client. The IP address in human-readable
+        -: 1817: * format will be written to a new char* buffer, the address of which will be
+        -: 1818: * stored in client->clientname.
+        -: 1819: * @return: 0 - OK, -1 - failed.
+        -: 1820: **/
+       11: 1821:int set_peername(int net, CLIENT *client) {
+        -: 1822:	struct sockaddr_storage netaddr;
+       11: 1823:	socklen_t addrinlen = sizeof( struct sockaddr_storage );
+        -: 1824:	struct addrinfo hints;
+       11: 1825:	struct addrinfo *ai = NULL;
+        -: 1826:	char peername[NI_MAXHOST];
+        -: 1827:	char netname[NI_MAXHOST];
+       11: 1828:	char *tmp = NULL;
+        -: 1829:	int i;
+        -: 1830:	int e;
+        -: 1831:
+       11: 1832:	if (getpeername(net, (struct sockaddr *) &(client->clientaddr), &addrinlen) < 0) {
+    #####: 1833:		msg(LOG_INFO, "getpeername failed: %m");
+    #####: 1834:		return -1;
+        -: 1835:	}
+        -: 1836:
+       11: 1837:	if((e = getnameinfo((struct sockaddr *)&(client->clientaddr), addrinlen,
+        -: 1838:			peername, sizeof (peername), NULL, 0, NI_NUMERICHOST))) {
+    #####: 1839:		msg(LOG_INFO, "getnameinfo failed: %s", gai_strerror(e));
+    #####: 1840:		return -1;
+        -: 1841:	}
+        -: 1842:
+       11: 1843:	memset(&hints, '\0', sizeof (hints));
+       11: 1844:	hints.ai_flags = AI_ADDRCONFIG;
+       11: 1845:	e = getaddrinfo(peername, NULL, &hints, &ai);
+        -: 1846:
+       11: 1847:	if(e != 0) {
+    #####: 1848:		msg(LOG_INFO, "getaddrinfo failed: %s", gai_strerror(e));
+    #####: 1849:		freeaddrinfo(ai);
+    #####: 1850:		return -1;
+        -: 1851:	}
+        -: 1852:
+       11: 1853:	switch(client->server->virtstyle) {
+        -: 1854:		case VIRT_NONE:
+    #####: 1855:			msg(LOG_DEBUG, "virtualization is off");
+    #####: 1856:			client->exportname=g_strdup(client->server->exportname);
+    #####: 1857:			break;
+        -: 1858:		case VIRT_IPHASH:
+    #####: 1859:			msg(LOG_DEBUG, "virtstyle iphash");
+    #####: 1860:			for(i=0;i<strlen(peername);i++) {
+    #####: 1861:				if(peername[i]=='.') {
+    #####: 1862:					peername[i]='/';
+        -: 1863:				}
+        -: 1864:			}
+        -: 1865:		case VIRT_IPLIT:
+       11: 1866:			msg(LOG_DEBUG, "virtstyle ipliteral");
+       11: 1867:			client->exportname=g_strdup_printf(client->server->exportname, peername);
+       11: 1868:			break;
+        -: 1869:		case VIRT_CIDR:
+    #####: 1870:			msg(LOG_DEBUG, "virtstyle cidr %d", client->server->cidrlen);
+    #####: 1871:			memcpy(&netaddr, &(client->clientaddr), addrinlen);
+        -: 1872:			int addrbits;
+    #####: 1873:			assert((ai->ai_family == AF_INET) || (ai->ai_family == AF_INET6));
+    #####: 1874:			if(ai->ai_family == AF_INET) {
+    #####: 1875:				addrbits = 32;
+    #####: 1876:			} else if(ai->ai_family == AF_INET6) {
+    #####: 1877:				addrbits = 128;
+        -: 1878:			}
+    #####: 1879:			uint8_t* addrptr = (uint8_t*)(((struct sockaddr*)&netaddr)->sa_data);
+    #####: 1880:			for(int i = 0; i < addrbits; i+=8) {
+    #####: 1881:				int masklen = client->server->cidrlen - i;
+    #####: 1882:				masklen = masklen > 0 ? masklen : 0;
+    #####: 1883:				uint8_t mask = getmaskbyte(masklen);
+    #####: 1884:				*addrptr &= mask;
+    #####: 1885:				addrptr++;
+        -: 1886:			}
+    #####: 1887:			getnameinfo((struct sockaddr *) &netaddr, addrinlen,
+        -: 1888:							netname, sizeof (netname), NULL, 0, NI_NUMERICHOST);
+    #####: 1889:			tmp=g_strdup_printf("%s/%s", netname, peername);
+        -: 1890:
+    #####: 1891:			if(tmp != NULL)
+    #####: 1892:			  client->exportname=g_strdup_printf(client->server->exportname, tmp);
+        -: 1893:
+    #####: 1894:			break;
+        -: 1895:	}
+        -: 1896:
+       11: 1897:	freeaddrinfo(ai);
+       11: 1898:        msg(LOG_INFO, "connect from %s, assigned file is %s",
+        -: 1899:            peername, client->exportname);
+       11: 1900:	client->clientname=g_strdup(peername);
+       11: 1901:	return 0;
+        -: 1902:}
+        -: 1903:
+        -: 1904:/**
+        -: 1905: * Destroy a pid_t*
+        -: 1906: * @param data a pointer to pid_t which should be freed
+        -: 1907: **/
+       11: 1908:void destroy_pid_t(gpointer data) {
+       11: 1909:	g_free(data);
+       11: 1910:}
+        -: 1911:
+        -: 1912:static pid_t
+        7: 1913:spawn_child()
+        -: 1914:{
+        -: 1915:        pid_t pid;
+        -: 1916:        sigset_t newset;
+        -: 1917:        sigset_t oldset;
+        -: 1918:
+        7: 1919:        sigemptyset(&newset);
+        7: 1920:        sigaddset(&newset, SIGCHLD);
+        7: 1921:        sigaddset(&newset, SIGTERM);
+        7: 1922:        sigprocmask(SIG_BLOCK, &newset, &oldset);
+        7: 1923:        pid = fork();
+       14: 1924:        if (pid < 0) {
+    #####: 1925:                msg(LOG_ERR, "Could not fork (%s)", strerror(errno));
+    #####: 1926:                goto out;
+        -: 1927:        }
+       14: 1928:        if (pid > 0) { /* Parent */
+        -: 1929:                pid_t *pidp;
+        -: 1930:
+        7: 1931:                pidp = g_malloc(sizeof(pid_t));
+        7: 1932:                *pidp = pid;
+        7: 1933:                g_hash_table_insert(children, pidp, pidp);
+        7: 1934:                goto out;
+        -: 1935:        }
+        -: 1936:        /* Child */
+        7: 1937:        signal(SIGCHLD, SIG_DFL);
+        7: 1938:        signal(SIGTERM, SIG_DFL);
+        7: 1939:        signal(SIGHUP, SIG_DFL);
+        -: 1940:out:
+       14: 1941:        sigprocmask(SIG_SETMASK, &oldset, NULL);
+       14: 1942:        return pid;
+        -: 1943:}
+        -: 1944:
+        -: 1945:static int
+       12: 1946:socket_accept(const int sock)
+        -: 1947:{
+        -: 1948:        struct sockaddr_storage addrin;
+       12: 1949:        socklen_t addrinlen = sizeof(addrin);
+        -: 1950:        int net;
+        -: 1951:
+       12: 1952:        net = accept(sock, (struct sockaddr *) &addrin, &addrinlen);
+       12: 1953:        if (net < 0) {
+    #####: 1954:                err_nonfatal("Failed to accept socket connection: %m");
+        -: 1955:        }
+        -: 1956:
+       12: 1957:        return net;
+        -: 1958:}
+        -: 1959:
+        -: 1960:static void
+        7: 1961:handle_modern_connection(GArray *const servers, const int sock)
+        -: 1962:{
+        -: 1963:        int net;
+        -: 1964:        pid_t pid;
+        7: 1965:        CLIENT *client = NULL;
+        -: 1966:        int sock_flags_old;
+        -: 1967:        int sock_flags_new;
+        -: 1968:
+        7: 1969:        net = socket_accept(sock);
+        7: 1970:        if (net < 0)
+    #####: 1971:                return;
+        -: 1972:
+        7: 1973:        if (!dontfork) {
+        7: 1974:                pid = spawn_child();
+       14: 1975:                if (pid) {
+        7: 1976:                        if (pid > 0)
+        7: 1977:                                msg(LOG_INFO, "Spawned a child process");
+        7: 1978:                        if (pid < 0)
+    #####: 1979:                                msg(LOG_ERR, "Failed to spawn a child process");
+        7: 1980:                        close(net);
+        7: 1981:                        return;
+        -: 1982:                }
+        -: 1983:                /* Child just continues. */
+        -: 1984:        }
+        -: 1985:
+        7: 1986:        client = negotiate(net, NULL, servers, NEG_INIT | NEG_MODERN);
+        7: 1987:        if (!client) {
+        1: 1988:                msg(LOG_ERR, "Modern initial negotiation failed");
+        1: 1989:                goto handler_err;
+        -: 1990:        }
+        -: 1991:
+        6: 1992:        if (client->server->max_connections > 0 &&
+    #####: 1993:           g_hash_table_size(children) >= client->server->max_connections) {
+    #####: 1994:                msg(LOG_ERR, "Max connections (%d) reached",
+        -: 1995:                    client->server->max_connections);
+    #####: 1996:                goto handler_err;
+        -: 1997:        }
+        -: 1998:
+        6: 1999:        sock_flags_old = fcntl(net, F_GETFL, 0);
+        6: 2000:        if (sock_flags_old == -1) {
+    #####: 2001:                msg(LOG_ERR, "Failed to get socket flags");
+    #####: 2002:                goto handler_err;
+        -: 2003:        }
+        -: 2004:
+        6: 2005:        sock_flags_new = sock_flags_old & ~O_NONBLOCK;
+        6: 2006:        if (sock_flags_new != sock_flags_old &&
+    #####: 2007:            fcntl(net, F_SETFL, sock_flags_new) == -1) {
+    #####: 2008:                msg(LOG_ERR, "Failed to set socket to blocking mode");
+    #####: 2009:                goto handler_err;
+        -: 2010:        }
+        -: 2011:
+        6: 2012:        if (set_peername(net, client)) {
+    #####: 2013:                msg(LOG_ERR, "Failed to set peername");
+    #####: 2014:                goto handler_err;
+        -: 2015:        }
+        -: 2016:
+        6: 2017:        if (!authorized_client(client)) {
+    #####: 2018:                msg(LOG_INFO, "Client '%s' is not authorized to access",
+        -: 2019:                    client->clientname);
+    #####: 2020:                goto handler_err;
+        -: 2021:        }
+        -: 2022:
+        6: 2023:        if (!dontfork) {
+        -: 2024:                int i;
+        -: 2025:
+        -: 2026:                /* Free all root server resources here, because we are
+        -: 2027:                 * currently in the child process serving one specific
+        -: 2028:                 * connection. These are not simply needed anymore. */
+        6: 2029:                g_hash_table_destroy(children);
+        6: 2030:                children = NULL;
+       12: 2031:                for (i = 0; i < modernsocks->len; i++) {
+        6: 2032:                        close(g_array_index(modernsocks, int, i));
+        -: 2033:                }
+        6: 2034:                g_array_free(modernsocks, TRUE);
+        -: 2035:
+        -: 2036:                /* Now that we are in the child process after a
+        -: 2037:                 * succesful negotiation, we do not need the list of
+        -: 2038:                 * servers anymore, get rid of it.*/
+        -: 2039:
+       12: 2040:                for (i = 0; i < servers->len; i++) {
+        6: 2041:                        const SERVER *const server = &g_array_index(servers, SERVER, i);
+        6: 2042:                        close(server->socket);
+        -: 2043:                }
+        -: 2044:
+        -: 2045:                /* FALSE does not free the
+        -: 2046:                   actual data. This is required,
+        -: 2047:                   because the client has a
+        -: 2048:                   direct reference into that
+        -: 2049:                   data, and otherwise we get a
+        -: 2050:                   segfault... */
+        6: 2051:                g_array_free(servers, FALSE);
+        -: 2052:        }
+        -: 2053:
+        6: 2054:        msg(LOG_INFO, "Starting to serve");
+        6: 2055:        serveconnection(client);
+        6: 2056:        exit(EXIT_SUCCESS);
+        -: 2057:
+        -: 2058:handler_err:
+        1: 2059:        g_free(client);
+        1: 2060:        close(net);
+        -: 2061:
+        1: 2062:        if (!dontfork) {
+        1: 2063:                exit(EXIT_FAILURE);
+        -: 2064:        }
+        -: 2065:}
+        -: 2066:
+        -: 2067:static void
+        5: 2068:handle_oldstyle_connection(GArray *const servers, SERVER *const serve)
+        -: 2069:{
+        -: 2070:	int net;
+        5: 2071:	CLIENT *client = NULL;
+        -: 2072:	int sock_flags_old;
+        -: 2073:	int sock_flags_new;
+        -: 2074:
+        5: 2075:	net = socket_accept(serve->socket);
+        5: 2076:	if (net < 0)
+        5: 2077:		return;
+        -: 2078:
+        5: 2079:	if(serve->max_connections > 0 &&
+    #####: 2080:	   g_hash_table_size(children) >= serve->max_connections) {
+    #####: 2081:		msg(LOG_INFO, "Max connections reached");
+    #####: 2082:		goto handle_connection_out;
+        -: 2083:	}
+        5: 2084:	if((sock_flags_old = fcntl(net, F_GETFL, 0)) == -1) {
+    #####: 2085:		err("fcntl F_GETFL");
+        -: 2086:	}
+        5: 2087:	sock_flags_new = sock_flags_old & ~O_NONBLOCK;
+        5: 2088:	if (sock_flags_new != sock_flags_old &&
+    #####: 2089:	    fcntl(net, F_SETFL, sock_flags_new) == -1) {
+    #####: 2090:		err("fcntl F_SETFL ~O_NONBLOCK");
+        -: 2091:	}
+        -: 2092:
+        5: 2093:	client = g_new0(CLIENT, 1);
+        5: 2094:	client->server=serve;
+        5: 2095:	client->exportsize=OFFT_MAX;
+        5: 2096:	client->net=net;
+        5: 2097:	client->transactionlogfd = -1;
+        -: 2098:
+        5: 2099:	if (set_peername(net, client)) {
+    #####: 2100:		goto handle_connection_out;
+        -: 2101:	}
+        5: 2102:	if (!authorized_client(client)) {
+    #####: 2103:		msg(LOG_INFO, "Unauthorized client");
+    #####: 2104:		goto handle_connection_out;
+        -: 2105:	}
+        5: 2106:	msg(LOG_INFO, "Authorized client");
+        -: 2107:
+        5: 2108:	if (!dontfork) {
+        -: 2109:		pid_t pid;
+        -: 2110:		int i;
+        -: 2111:		sigset_t newset;
+        -: 2112:		sigset_t oldset;
+        -: 2113:
+        5: 2114:		sigemptyset(&newset);
+        5: 2115:		sigaddset(&newset, SIGCHLD);
+        5: 2116:		sigaddset(&newset, SIGTERM);
+        5: 2117:		sigprocmask(SIG_BLOCK, &newset, &oldset);
+        5: 2118:		if ((pid = fork()) < 0) {
+    #####: 2119:			msg(LOG_INFO, "Could not fork (%s)", strerror(errno));
+    #####: 2120:			sigprocmask(SIG_SETMASK, &oldset, NULL);
+    #####: 2121:			goto handle_connection_out;
+        -: 2122:		}
+       10: 2123:		if (pid > 0) { /* parent */
+        -: 2124:			pid_t *pidp;
+        -: 2125:
+        5: 2126:			pidp = g_malloc(sizeof(pid_t));
+        5: 2127:			*pidp = pid;
+        5: 2128:			g_hash_table_insert(children, pidp, pidp);
+        5: 2129:			sigprocmask(SIG_SETMASK, &oldset, NULL);
+        5: 2130:			goto handle_connection_out;
+        -: 2131:		}
+        -: 2132:		/* child */
+        5: 2133:		signal(SIGCHLD, SIG_DFL);
+        5: 2134:		signal(SIGTERM, SIG_DFL);
+        5: 2135:		signal(SIGHUP, SIG_DFL);
+        5: 2136:		sigprocmask(SIG_SETMASK, &oldset, NULL);
+        -: 2137:
+        5: 2138:		g_hash_table_destroy(children);
+        5: 2139:		children = NULL;
+       12: 2140:		for(i=0;i<servers->len;i++) {
+        7: 2141:			close(g_array_index(servers, SERVER, i).socket);
+        -: 2142:		}
+        -: 2143:		/* FALSE does not free the
+        -: 2144:		   actual data. This is required,
+        -: 2145:		   because the client has a
+        -: 2146:		   direct reference into that
+        -: 2147:		   data, and otherwise we get a
+        -: 2148:		   segfault... */
+        5: 2149:		g_array_free(servers, FALSE);
+        8: 2150:		for(i=0;i<modernsocks->len;i++) {
+        3: 2151:			close(g_array_index(modernsocks, int, i));
+        -: 2152:		}
+        5: 2153:		g_array_free(modernsocks, TRUE);
+        -: 2154:	}
+        -: 2155:
+        5: 2156:	msg(LOG_INFO, "Starting to serve");
+        5: 2157:	serveconnection(client);
+        4: 2158:	exit(EXIT_SUCCESS);
+        -: 2159:
+        -: 2160:handle_connection_out:
+        5: 2161:	g_free(client);
+        5: 2162:	close(net);
+        -: 2163:}
+        -: 2164:
+        -: 2165:/**
+        -: 2166: * Return the index of the server whose servename matches the given
+        -: 2167: * name.
+        -: 2168: *
+        -: 2169: * @param servename a string to match
+        -: 2170: * @param servers an array of servers
+        -: 2171: * @return the first index of the server whose servename matches the
+        -: 2172: *         given name or -1 if one cannot be found
+        -: 2173: **/
+    #####: 2174:static int get_index_by_servename(const gchar *const servename,
+        -: 2175:                                  const GArray *const servers) {
+        -: 2176:        int i;
+        -: 2177:
+    #####: 2178:        for (i = 0; i < servers->len; ++i) {
+    #####: 2179:                const SERVER server = g_array_index(servers, SERVER, i);
+        -: 2180:
+    #####: 2181:                if (strcmp(servename, server.servename) == 0)
+    #####: 2182:                        return i;
+        -: 2183:        }
+        -: 2184:
+    #####: 2185:        return -1;
+        -: 2186:}
+        -: 2187:
+        -: 2188:int setup_serve(SERVER *const serve, GError **const gerror);
+        -: 2189:
+        -: 2190:/**
+        -: 2191: * Parse configuration files and add servers to the array if they don't
+        -: 2192: * already exist there. The existence is tested by comparing
+        -: 2193: * servenames. A server is appended to the array only if its servename
+        -: 2194: * is unique among all other servers.
+        -: 2195: *
+        -: 2196: * @param servers an array of servers
+        -: 2197: * @return the number of new servers appended to the array, or -1 in
+        -: 2198: *         case of an error
+        -: 2199: **/
+    #####: 2200:static int append_new_servers(GArray *const servers, GError **const gerror) {
+        -: 2201:        int i;
+        -: 2202:        GArray *new_servers;
+    #####: 2203:        const int old_len = servers->len;
+    #####: 2204:        int retval = -1;
+        -: 2205:        struct generic_conf genconf;
+        -: 2206:
+    #####: 2207:        new_servers = parse_cfile(config_file_pos, &genconf, true, gerror);
+    #####: 2208:        if (!new_servers)
+    #####: 2209:                goto out;
+        -: 2210:
+    #####: 2211:        for (i = 0; i < new_servers->len; ++i) {
+    #####: 2212:                SERVER new_server = g_array_index(new_servers, SERVER, i);
+        -: 2213:
+    #####: 2214:                if (new_server.servename
+    #####: 2215:                    && -1 == get_index_by_servename(new_server.servename,
+        -: 2216:                                                    servers)) {
+    #####: 2217:                        if (setup_serve(&new_server, gerror) == -1)
+    #####: 2218:                                goto out;
+    #####: 2219:                        if (append_serve(&new_server, servers) == -1)
+    #####: 2220:                                goto out;
+        -: 2221:                }
+        -: 2222:        }
+        -: 2223:
+    #####: 2224:        retval = servers->len - old_len;
+        -: 2225:out:
+    #####: 2226:        g_array_free(new_servers, TRUE);
+        -: 2227:
+    #####: 2228:        return retval;
+        -: 2229:}
+        -: 2230:
+        -: 2231:/**
+        -: 2232: * Loop through the available servers, and serve them. Never returns.
+        -: 2233: **/
+       10: 2234:void serveloop(GArray* servers) {
+        -: 2235:	int i;
+        -: 2236:	int max;
+        -: 2237:	fd_set mset;
+        -: 2238:	fd_set rset;
+        -: 2239:
+        -: 2240:	/* 
+        -: 2241:	 * Set up the master fd_set. The set of descriptors we need
+        -: 2242:	 * to select() for never changes anyway and it buys us a *lot*
+        -: 2243:	 * of time to only build this once. However, if we ever choose
+        -: 2244:	 * to not fork() for clients anymore, we may have to revisit
+        -: 2245:	 * this.
+        -: 2246:	 */
+       10: 2247:	max=0;
+       10: 2248:	FD_ZERO(&mset);
+       21: 2249:	for(i=0;i<servers->len;i++) {
+        -: 2250:		int sock;
+       11: 2251:		if((sock=(g_array_index(servers, SERVER, i)).socket) >= 0) {
+        5: 2252:			FD_SET(sock, &mset);
+        5: 2253:			max=sock>max?sock:max;
+        -: 2254:		}
+        -: 2255:	}
+       18: 2256:	for(i=0;i<modernsocks->len;i++) {
+        8: 2257:		int sock = g_array_index(modernsocks, int, i);
+        8: 2258:		FD_SET(sock, &mset);
+        8: 2259:		max=sock>max?sock:max;
+        -: 2260:	}
+        -: 2261:	for(;;) {
+        -: 2262:                /* SIGHUP causes the root server process to reconfigure
+        -: 2263:                 * itself and add new export servers for each newly
+        -: 2264:                 * found export configuration group, i.e. spawn new
+        -: 2265:                 * server processes for each previously non-existent
+        -: 2266:                 * export. This does not alter old runtime configuration
+        -: 2267:                 * but just appends new exports. */
+       33: 2268:                if (is_sighup_caught) {
+        -: 2269:                        int n;
+    #####: 2270:                        GError *gerror = NULL;
+        -: 2271:
+    #####: 2272:                        msg(LOG_INFO, "reconfiguration request received");
+    #####: 2273:                        is_sighup_caught = 0; /* Reset to allow catching
+        -: 2274:                                               * it again. */
+        -: 2275:
+    #####: 2276:                        n = append_new_servers(servers, &gerror);
+    #####: 2277:                        if (n == -1)
+    #####: 2278:                                msg(LOG_ERR, "failed to append new servers: %s",
+        -: 2279:                                    gerror->message);
+        -: 2280:
+    #####: 2281:                        for (i = servers->len - n; i < servers->len; ++i) {
+    #####: 2282:                                const SERVER server = g_array_index(servers,
+        -: 2283:                                                                    SERVER, i);
+        -: 2284:
+    #####: 2285:                                if (server.socket >= 0) {
+    #####: 2286:                                        FD_SET(server.socket, &mset);
+    #####: 2287:                                        max = server.socket > max ? server.socket : max;
+        -: 2288:                                }
+        -: 2289:
+    #####: 2290:                                msg(LOG_INFO, "reconfigured new server: %s",
+        -: 2291:                                    server.servename);
+        -: 2292:                        }
+        -: 2293:                }
+        -: 2294:
+       33: 2295:		memcpy(&rset, &mset, sizeof(fd_set));
+       33: 2296:		if(select(max+1, &rset, NULL, NULL, NULL)>0) {
+        -: 2297:
+        -: 2298:			DEBUG("accept, ");
+       22: 2299:			for(i=0; i < modernsocks->len; i++) {
+       10: 2300:				int sock = g_array_index(modernsocks, int, i);
+       10: 2301:				if(!FD_ISSET(sock, &rset)) {
+        3: 2302:					continue;
+        -: 2303:				}
+        -: 2304:
+        7: 2305:				handle_modern_connection(servers, sock);
+        -: 2306:			}
+       26: 2307:			for(i=0; i < servers->len; i++) {
+        -: 2308:				SERVER *serve;
+        -: 2309:
+       14: 2310:				serve=&(g_array_index(servers, SERVER, i));
+       14: 2311:				if(serve->socket < 0) {
+        7: 2312:					continue;
+        -: 2313:				}
+        7: 2314:				if(FD_ISSET(serve->socket, &rset)) {
+        5: 2315:					handle_oldstyle_connection(servers, serve);
+        -: 2316:				}
+        -: 2317:			}
+        -: 2318:		}
+       23: 2319:	}
+        -: 2320:}
+        -: 2321:void serveloop(GArray* servers) G_GNUC_NORETURN;
+        -: 2322:
+        -: 2323:/**
+        -: 2324: * Set server socket options.
+        -: 2325: *
+        -: 2326: * @param socket a socket descriptor of the server
+        -: 2327: *
+        -: 2328: * @param gerror a pointer to an error object pointer used for reporting
+        -: 2329: *        errors. On error, if gerror is not NULL, *gerror is set and -1
+        -: 2330: *        is returned.
+        -: 2331: *
+        -: 2332: * @return 0 on success, -1 on error
+        -: 2333: **/
+       13: 2334:int dosockopts(const int socket, GError **const gerror) {
+        -: 2335:#ifndef sun
+       13: 2336:	int yes=1;
+        -: 2337:#else
+        -: 2338:	char yes='1';
+        -: 2339:#endif /* sun */
+        -: 2340:	struct linger l;
+        -: 2341:
+        -: 2342:	/* lose the pesky "Address already in use" error message */
+       13: 2343:	if (setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
+    #####: 2344:                g_set_error(gerror, NBDS_ERR, NBDS_ERR_SO_REUSEADDR,
+        -: 2345:                            "failed to set socket option SO_REUSEADDR: %s",
+    #####: 2346:                            strerror(errno));
+    #####: 2347:                return -1;
+        -: 2348:	}
+       13: 2349:	l.l_onoff = 1;
+       13: 2350:	l.l_linger = 10;
+       13: 2351:	if (setsockopt(socket,SOL_SOCKET,SO_LINGER,&l,sizeof(l)) == -1) {
+    #####: 2352:                g_set_error(gerror, NBDS_ERR, NBDS_ERR_SO_LINGER,
+        -: 2353:                            "failed to set socket option SO_LINGER: %s",
+    #####: 2354:                            strerror(errno));
+    #####: 2355:                return -1;
+        -: 2356:	}
+       13: 2357:	if (setsockopt(socket,SOL_SOCKET,SO_KEEPALIVE,&yes,sizeof(int)) == -1) {
+    #####: 2358:                g_set_error(gerror, NBDS_ERR, NBDS_ERR_SO_KEEPALIVE,
+        -: 2359:                            "failed to set socket option SO_KEEPALIVE: %s",
+    #####: 2360:                            strerror(errno));
+    #####: 2361:                return -1;
+        -: 2362:	}
+        -: 2363:
+       13: 2364:        return 0;
+        -: 2365:}
+        -: 2366:
+        -: 2367:/**
+        -: 2368: * Connect a server's socket.
+        -: 2369: *
+        -: 2370: * @param serve the server we want to connect.
+        -: 2371: **/
+       11: 2372:int setup_serve(SERVER *const serve, GError **const gerror) {
+        -: 2373:	struct addrinfo hints;
+       11: 2374:	struct addrinfo *ai = NULL;
+       11: 2375:	gchar *port = NULL;
+        -: 2376:	int e;
+       11: 2377:        int retval = -1;
+        -: 2378:
+        -: 2379:        /* Without this, it's possible that socket == 0, even if it's
+        -: 2380:         * not initialized at all. And that would be wrong because 0 is
+        -: 2381:         * totally legal value for properly initialized descriptor. This
+        -: 2382:         * line is required to ensure that unused/uninitialized
+        -: 2383:         * descriptors are marked as such (new style configuration
+        -: 2384:         * case). Currently, servers are being initialized in multiple
+        -: 2385:         * places, and some of the them do the socket initialization
+        -: 2386:         * incorrectly. This is the only point common to all code paths,
+        -: 2387:         * and therefore setting -1 is put here. However, the whole
+        -: 2388:         * server initialization procedure should be extracted to its
+        -: 2389:         * own function and all code paths wanting to mess with servers
+        -: 2390:         * should initialize servers with that function.
+        -: 2391:         * 
+        -: 2392:         * TODO: fix server initialization */
+       11: 2393:        serve->socket = -1;
+        -: 2394:
+       11: 2395:	if(!(glob_flags & F_OLDSTYLE)) {
+        6: 2396:		return serve->servename ? 1 : 0;
+        -: 2397:	}
+        5: 2398:	memset(&hints,'\0',sizeof(hints));
+        5: 2399:	hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG | AI_NUMERICSERV;
+        5: 2400:	hints.ai_socktype = SOCK_STREAM;
+        5: 2401:	hints.ai_family = serve->socket_family;
+        -: 2402:
+        5: 2403:	port = g_strdup_printf("%d", serve->port);
+        5: 2404:	if (!port) {
+    #####: 2405:                g_set_error(gerror, NBDS_ERR, NBDS_ERR_SYS,
+        -: 2406:                            "failed to open an export socket: "
+        -: 2407:                            "failed to convert a port number to a string: %s",
+    #####: 2408:                            strerror(errno));
+    #####: 2409:                goto out;
+        -: 2410:        }
+        -: 2411:
+        5: 2412:	e = getaddrinfo(serve->listenaddr,port,&hints,&ai);
+        -: 2413:
+        5: 2414:	g_free(port);
+        -: 2415:
+        5: 2416:	if(e != 0) {
+    #####: 2417:                g_set_error(gerror, NBDS_ERR, NBDS_ERR_GAI,
+        -: 2418:                            "failed to open an export socket: "
+        -: 2419:                            "failed to get address info: %s",
+        -: 2420:                            gai_strerror(e));
+    #####: 2421:                goto out;
+        -: 2422:	}
+        -: 2423:
+        5: 2424:	if(serve->socket_family == AF_UNSPEC)
+    #####: 2425:		serve->socket_family = ai->ai_family;
+        -: 2426:
+        -: 2427:#ifdef WITH_SDP
+        -: 2428:	if ((serve->flags) && F_SDP) {
+        -: 2429:		if (ai->ai_family == AF_INET)
+        -: 2430:			ai->ai_family = AF_INET_SDP;
+        -: 2431:		else (ai->ai_family == AF_INET6)
+        -: 2432:			ai->ai_family = AF_INET6_SDP;
+        -: 2433:	}
+        -: 2434:#endif
+        5: 2435:	if ((serve->socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) {
+    #####: 2436:                g_set_error(gerror, NBDS_ERR, NBDS_ERR_SOCKET,
+        -: 2437:                            "failed to open an export socket: "
+        -: 2438:                            "failed to create a socket: %s",
+    #####: 2439:                            strerror(errno));
+    #####: 2440:                goto out;
+        -: 2441:        }
+        -: 2442:
+        5: 2443:	if (dosockopts(serve->socket, gerror) == -1) {
+    #####: 2444:                g_prefix_error(gerror, "failed to open an export socket: ");
+    #####: 2445:                goto out;
+        -: 2446:        }
+        -: 2447:
+        -: 2448:	DEBUG("Waiting for connections... bind, ");
+        5: 2449:	e = bind(serve->socket, ai->ai_addr, ai->ai_addrlen);
+        5: 2450:	if (e != 0 && errno != EADDRINUSE) {
+    #####: 2451:                g_set_error(gerror, NBDS_ERR, NBDS_ERR_BIND,
+        -: 2452:                            "failed to open an export socket: "
+        -: 2453:                            "failed to bind an address to a socket: %s",
+    #####: 2454:                            strerror(errno));
+    #####: 2455:                goto out;
+        -: 2456:        }
+        -: 2457:	DEBUG("listen, ");
+        5: 2458:	if (listen(serve->socket, 1) < 0) {
+    #####: 2459:                g_set_error(gerror, NBDS_ERR, NBDS_ERR_BIND,
+        -: 2460:                            "failed to open an export socket: "
+        -: 2461:                            "failed to start listening on a socket: %s",
+    #####: 2462:                            strerror(errno));
+    #####: 2463:                goto out;
+        -: 2464:        }
+        -: 2465:
+        5: 2466:        retval = serve->servename ? 1 : 0;
+        -: 2467:out:
+        -: 2468:
+        5: 2469:        if (retval == -1 && serve->socket >= 0) {
+    #####: 2470:                close(serve->socket);
+    #####: 2471:                serve->socket = -1;
+        -: 2472:        }
+        5: 2473:	freeaddrinfo (ai);
+        -: 2474:
+        5: 2475:        return retval;
+        -: 2476:}
+        -: 2477:
+        8: 2478:int open_modern(const gchar *const addr, const gchar *const port,
+        -: 2479:                GError **const gerror) {
+        -: 2480:	struct addrinfo hints;
+        8: 2481:	struct addrinfo* ai = NULL;
+        -: 2482:	struct addrinfo* ai_bak;
+        -: 2483:	struct sock_flags;
+        -: 2484:	int e;
+        8: 2485:        int retval = -1;
+        8: 2486:	int sock = -1;
+        -: 2487:
+        8: 2488:	memset(&hints, '\0', sizeof(hints));
+        8: 2489:	hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
+        8: 2490:	hints.ai_socktype = SOCK_STREAM;
+        8: 2491:	hints.ai_family = AF_UNSPEC;
+        8: 2492:	hints.ai_protocol = IPPROTO_TCP;
+        8: 2493:	e = getaddrinfo(addr, port ? port : NBD_DEFAULT_PORT, &hints, &ai);
+        8: 2494:	ai_bak = ai;
+        8: 2495:	if(e != 0) {
+    #####: 2496:                g_set_error(gerror, NBDS_ERR, NBDS_ERR_GAI,
+        -: 2497:                            "failed to open a modern socket: "
+        -: 2498:                            "failed to get address info: %s",
+        -: 2499:                            gai_strerror(e));
+    #####: 2500:                goto out;
+        -: 2501:	}
+        -: 2502:
+       24: 2503:	while(ai != NULL) {
+        8: 2504:		sock = -1;
+        -: 2505:
+        8: 2506:		if((sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))<0) {
+    #####: 2507:			g_set_error(gerror, NBDS_ERR, NBDS_ERR_SOCKET,
+        -: 2508:				    "failed to open a modern socket: "
+        -: 2509:				    "failed to create a socket: %s",
+    #####: 2510:				    strerror(errno));
+    #####: 2511:			goto out;
+        -: 2512:		}
+        -: 2513:
+        8: 2514:		if (dosockopts(sock, gerror) == -1) {
+    #####: 2515:			g_prefix_error(gerror, "failed to open a modern socket: ");
+    #####: 2516:			goto out;
+        -: 2517:		}
+        -: 2518:
+        8: 2519:		if(bind(sock, ai->ai_addr, ai->ai_addrlen)) {
+        -: 2520:			/* This is so wrong. 
+        -: 2521:			 * 
+        -: 2522:			 * Linux will return multiple entries for the
+        -: 2523:			 * same system when we ask it for something
+        -: 2524:			 * AF_UNSPEC, even though the first entry will
+        -: 2525:			 * listen to both protocols. Other systems will
+        -: 2526:			 * return multiple entries too, but we actually
+        -: 2527:			 * do need to open both. Sigh.
+        -: 2528:			 *
+        -: 2529:			 * Handle it by ignoring EADDRINUSE if we've
+        -: 2530:			 * already got at least one socket open
+        -: 2531:			 */
+    #####: 2532:			if(errno == EADDRINUSE && modernsocks->len > 0) {
+    #####: 2533:				goto next;
+        -: 2534:			}
+    #####: 2535:			g_set_error(gerror, NBDS_ERR, NBDS_ERR_BIND,
+        -: 2536:				    "failed to open a modern socket: "
+        -: 2537:				    "failed to bind an address to a socket: %s",
+    #####: 2538:				    strerror(errno));
+    #####: 2539:			goto out;
+        -: 2540:		}
+        -: 2541:
+        8: 2542:		if(listen(sock, 10) <0) {
+    #####: 2543:			g_set_error(gerror, NBDS_ERR, NBDS_ERR_BIND,
+        -: 2544:				    "failed to open a modern socket: "
+        -: 2545:				    "failed to start listening on a socket: %s",
+    #####: 2546:				    strerror(errno));
+    #####: 2547:			goto out;
+        -: 2548:		}
+        8: 2549:		g_array_append_val(modernsocks, sock);
+        -: 2550:	next:
+        8: 2551:		ai = ai->ai_next;
+        -: 2552:	}
+        -: 2553:
+        8: 2554:        retval = 0;
+        -: 2555:out:
+        -: 2556:
+        8: 2557:        if (retval == -1 && sock >= 0) {
+    #####: 2558:                close(sock);
+        -: 2559:        }
+        8: 2560:	if(ai_bak)
+        8: 2561:		freeaddrinfo(ai_bak);
+        -: 2562:
+        8: 2563:        return retval;
+        -: 2564:}
+        -: 2565:
+        -: 2566:/**
+        -: 2567: * Connect our servers.
+        -: 2568: **/
+       10: 2569:void setup_servers(GArray *const servers, const gchar *const modernaddr,
+        -: 2570:                   const gchar *const modernport) {
+        -: 2571:	int i;
+        -: 2572:	struct sigaction sa;
+       10: 2573:	int want_modern=0;
+        -: 2574:
+       21: 2575:	for(i=0;i<servers->len;i++) {
+       11: 2576:                GError *gerror = NULL;
+       11: 2577:                SERVER *server = &g_array_index(servers, SERVER, i);
+        -: 2578:                int ret;
+        -: 2579:
+       11: 2580:		ret = setup_serve(server, &gerror);
+       11: 2581:                if (ret == -1) {
+    #####: 2582:                        msg(LOG_ERR, "failed to setup servers: %s",
+        -: 2583:                            gerror->message);
+    #####: 2584:                        g_clear_error(&gerror);
+    #####: 2585:                        exit(EXIT_FAILURE);
+        -: 2586:                }
+       11: 2587:                want_modern |= ret;
+        -: 2588:	}
+       10: 2589:	if(want_modern) {
+        8: 2590:                GError *gerror = NULL;
+        8: 2591:                if (open_modern(modernaddr, modernport, &gerror) == -1) {
+    #####: 2592:                        msg(LOG_ERR, "failed to setup servers: %s",
+        -: 2593:                            gerror->message);
+    #####: 2594:                        g_clear_error(&gerror);
+    #####: 2595:                        exit(EXIT_FAILURE);
+        -: 2596:                }
+        -: 2597:	}
+       10: 2598:	children=g_hash_table_new_full(g_int_hash, g_int_equal, NULL, destroy_pid_t);
+        -: 2599:
+       10: 2600:	sa.sa_handler = sigchld_handler;
+       10: 2601:	sigemptyset(&sa.sa_mask);
+       10: 2602:	sigaddset(&sa.sa_mask, SIGTERM);
+       10: 2603:	sa.sa_flags = SA_RESTART;
+       10: 2604:	if(sigaction(SIGCHLD, &sa, NULL) == -1)
+    #####: 2605:		err("sigaction: %m");
+        -: 2606:
+       10: 2607:	sa.sa_handler = sigterm_handler;
+       10: 2608:	sigemptyset(&sa.sa_mask);
+       10: 2609:	sigaddset(&sa.sa_mask, SIGCHLD);
+       10: 2610:	sa.sa_flags = SA_RESTART;
+       10: 2611:	if(sigaction(SIGTERM, &sa, NULL) == -1)
+    #####: 2612:		err("sigaction: %m");
+        -: 2613:
+       10: 2614:	sa.sa_handler = sighup_handler;
+       10: 2615:	sigemptyset(&sa.sa_mask);
+       10: 2616:	sa.sa_flags = SA_RESTART;
+       10: 2617:	if(sigaction(SIGHUP, &sa, NULL) == -1)
+    #####: 2618:		err("sigaction: %m");
+       10: 2619:}
+        -: 2620:
+        -: 2621:/**
+        -: 2622: * Go daemon (unless we specified at compile time that we didn't want this)
+        -: 2623: * @param serve the first server of our configuration. If its port is zero,
+        -: 2624: * 	then do not daemonize, because we're doing inetd then. This parameter
+        -: 2625: * 	is only used to create a PID file of the form
+        -: 2626: * 	/var/run/nbd-server.&lt;port&gt;.pid; it's not modified in any way.
+        -: 2627: **/
+        -: 2628:#if !defined(NODAEMON)
+       10: 2629:void daemonize(SERVER* serve) {
+        -: 2630:	FILE*pidf;
+        -: 2631:
+       10: 2632:	if(serve && !(serve->port)) {
+       10: 2633:		return;
+        -: 2634:	}
+       10: 2635:	if(daemon(0,0)<0) {
+    #####: 2636:		err("daemon");
+        -: 2637:	}
+       10: 2638:	if(!*pidftemplate) {
+    #####: 2639:		if(serve) {
+    #####: 2640:			strncpy(pidftemplate, "/var/run/nbd-server.%d.pid", 255);
+        -: 2641:		} else {
+    #####: 2642:			strncpy(pidftemplate, "/var/run/nbd-server.pid", 255);
+        -: 2643:		}
+        -: 2644:	}
+       10: 2645:	snprintf(pidfname, 255, pidftemplate, serve ? serve->port : 0);
+       10: 2646:	pidf=fopen(pidfname, "w");
+       10: 2647:	if(pidf) {
+       10: 2648:		fprintf(pidf,"%d\n", (int)getpid());
+       10: 2649:		fclose(pidf);
+        -: 2650:	} else {
+    #####: 2651:		perror("fopen");
+    #####: 2652:		fprintf(stderr, "Not fatal; continuing");
+        -: 2653:	}
+        -: 2654:}
+        -: 2655:#else
+        -: 2656:#define daemonize(serve)
+        -: 2657:#endif /* !defined(NODAEMON) */
+        -: 2658:
+        -: 2659:/*
+        -: 2660: * Everything beyond this point (in the file) is run in non-daemon mode.
+        -: 2661: * The stuff above daemonize() isn't.
+        -: 2662: */
+        -: 2663:
+        -: 2664:/**
+        -: 2665: * Set up user-ID and/or group-ID
+        -: 2666: **/
+       10: 2667:void dousers(const gchar *const username, const gchar *const groupname) {
+        -: 2668:	struct passwd *pw;
+        -: 2669:	struct group *gr;
+        -: 2670:	gchar* str;
+       10: 2671:	if (groupname) {
+    #####: 2672:		gr = getgrnam(groupname);
+    #####: 2673:		if(!gr) {
+    #####: 2674:			str = g_strdup_printf("Invalid group name: %s", groupname);
+    #####: 2675:			err(str);
+        -: 2676:		}
+    #####: 2677:		if(setgid(gr->gr_gid)<0) {
+    #####: 2678:			err("Could not set GID: %m"); 
+        -: 2679:		}
+        -: 2680:	}
+       10: 2681:	if (username) {
+    #####: 2682:		pw = getpwnam(username);
+    #####: 2683:		if(!pw) {
+    #####: 2684:			str = g_strdup_printf("Invalid user name: %s", username);
+    #####: 2685:			err(str);
+        -: 2686:		}
+    #####: 2687:		if(setuid(pw->pw_uid)<0) {
+    #####: 2688:			err("Could not set UID: %m");
+        -: 2689:		}
+        -: 2690:	}
+       10: 2691:}
+        -: 2692:
+        -: 2693:#ifndef ISSERVER
+    #####: 2694:void glib_message_syslog_redirect(const gchar *log_domain,
+        -: 2695:                                  GLogLevelFlags log_level,
+        -: 2696:                                  const gchar *message,
+        -: 2697:                                  gpointer user_data)
+        -: 2698:{
+    #####: 2699:    int level=LOG_DEBUG;
+        -: 2700:    
+    #####: 2701:    switch( log_level )
+        -: 2702:    {
+        -: 2703:      case G_LOG_FLAG_FATAL:
+        -: 2704:      case G_LOG_LEVEL_CRITICAL:
+        -: 2705:      case G_LOG_LEVEL_ERROR:    
+    #####: 2706:        level=LOG_ERR; 
+    #####: 2707:        break;
+        -: 2708:      case G_LOG_LEVEL_WARNING:
+    #####: 2709:        level=LOG_WARNING;
+    #####: 2710:        break;
+        -: 2711:      case G_LOG_LEVEL_MESSAGE:
+        -: 2712:      case G_LOG_LEVEL_INFO:
+    #####: 2713:        level=LOG_INFO;
+    #####: 2714:        break;
+        -: 2715:      case G_LOG_LEVEL_DEBUG:
+    #####: 2716:        level=LOG_DEBUG;
+    #####: 2717:	break;
+        -: 2718:      default:
+    #####: 2719:        level=LOG_ERR;
+        -: 2720:    }
+    #####: 2721:    syslog(level, "%s", message);
+    #####: 2722:}
+        -: 2723:#endif
+        -: 2724:
+        -: 2725:/**
+        -: 2726: * Main entry point...
+        -: 2727: **/
+       10: 2728:int main(int argc, char *argv[]) {
+        -: 2729:	SERVER *serve;
+        -: 2730:	GArray *servers;
+       10: 2731:	GError *err=NULL;
+        -: 2732:        struct generic_conf genconf;
+        -: 2733:
+       10: 2734:        memset(&genconf, 0, sizeof(struct generic_conf));
+        -: 2735:
+        -: 2736:	if (sizeof( struct nbd_request )!=28) {
+        -: 2737:		fprintf(stderr,"Bad size of structure. Alignment problems?\n");
+        -: 2738:		exit(EXIT_FAILURE) ;
+        -: 2739:	}
+        -: 2740:
+       10: 2741:	memset(pidftemplate, '\0', 256);
+        -: 2742:
+       10: 2743:	modernsocks = g_array_new(FALSE, FALSE, sizeof(int));
+        -: 2744:
+       10: 2745:	logging();
+       10: 2746:	config_file_pos = g_strdup(CFILE);
+       10: 2747:	serve=cmdline(argc, argv);
+        -: 2748:
+       10: 2749:        servers = parse_cfile(config_file_pos, &genconf, true, &err);
+        -: 2750:	
+        -: 2751:        /* Update global variables with parsed values. This will be
+        -: 2752:         * removed once we get rid of global configuration variables. */
+       10: 2753:        glob_flags   |= genconf.flags;
+        -: 2754:
+       10: 2755:	if(serve) {
+        2: 2756:		serve->socket_family = AF_UNSPEC;
+        -: 2757:
+        2: 2758:		append_serve(serve, servers);
+        -: 2759:     
+        2: 2760:		if (!(serve->port)) {
+        -: 2761:			CLIENT *client;
+        -: 2762:#ifndef ISSERVER
+        -: 2763:			/* You really should define ISSERVER if you're going to use
+        -: 2764:			 * inetd mode, but if you don't, closing stdout and stderr
+        -: 2765:			 * (which inetd had connected to the client socket) will let it
+        -: 2766:			 * work. */
+    #####: 2767:			close(1);
+    #####: 2768:			close(2);
+    #####: 2769:			open("/dev/null", O_WRONLY);
+    #####: 2770:			open("/dev/null", O_WRONLY);
+    #####: 2771:			g_log_set_default_handler( glib_message_syslog_redirect, NULL );
+        -: 2772:#endif
+    #####: 2773:			client=g_malloc(sizeof(CLIENT));
+    #####: 2774:			client->server=serve;
+    #####: 2775:			client->net=-1;
+    #####: 2776:			client->exportsize=OFFT_MAX;
+    #####: 2777:			if (set_peername(0, client))
+    #####: 2778:				exit(EXIT_FAILURE);
+    #####: 2779:			serveconnection(client);
+    #####: 2780:			return 0;
+        -: 2781:		}
+        -: 2782:	}
+        -: 2783:    
+       10: 2784:	if(!servers || !servers->len) {
+    #####: 2785:                if(err && !(err->domain == NBDS_ERR
+    #####: 2786:                            && err->code == NBDS_ERR_CFILE_NOTFOUND)) {
+    #####: 2787:			g_warning("Could not parse config file: %s", 
+        -: 2788:					err ? err->message : "Unknown error");
+        -: 2789:		}
+        -: 2790:	}
+       10: 2791:	if(serve) {
+        2: 2792:		g_warning("Specifying an export on the command line is deprecated.");
+        2: 2793:		g_warning("Please use a configuration file instead.");
+        -: 2794:	}
+        -: 2795:
+       10: 2796:	if((!serve) && (!servers||!servers->len)) {
+    #####: 2797:		if(err)
+    #####: 2798:			g_message("No configured exports; quitting.");
+    #####: 2799:		exit(EXIT_FAILURE);
+        -: 2800:	}
+       10: 2801:	if (!dontfork)
+       10: 2802:		daemonize(serve);
+       10: 2803:	setup_servers(servers, genconf.modernaddr, genconf.modernport);
+       10: 2804:	dousers(genconf.user, genconf.group);
+        -: 2805:
+       10: 2806:	serveloop(servers);
+        -: 2807:}
only in patch2:
unchanged:
--- nbd-3.8.orig/test.conf
+++ nbd-3.8/test.conf
@@ -0,0 +1,4 @@
+[generic]
+	allowlist = true
+[broken]
+	exportname=/dev/disk/by-id/mmc-SU02G_0x30c362de-part1
only in patch2:
unchanged:
--- nbd-3.8.orig/tests/run/testlib.sh
+++ nbd-3.8/tests/run/testlib.sh
@@ -0,0 +1,42 @@
+set -e
+
+if [ -z "$TMPDIR" ]
+then
+	TMPDIR=/tmp
+fi
+tmpdir=`mktemp -d $TMPDIR/tmp.XXXXXX`
+conffile=${tmpdir}/nbd.conf
+pidfile=${tmpdir}/nbd.pid
+tmpnam=${tmpdir}/nbd.dd
+mydir=$(dirname "`readlink -f $0`")
+cleanup="$2"
+PID=""
+
+set -e
+
+trap cleanup EXIT
+
+cleanup() {
+	if [ -f ${pidfile} ]
+	then
+		kill `cat ${pidfile}` || true
+	else
+		if [ ! -z "$PID" ]
+		then
+			kill $PID || true
+		fi
+	fi
+	if [ -z "$cleanup" ]
+	then
+		rm -rf $tmpdir
+	fi
+}
+
+devfile() {
+	size=${1:-4096}
+	dd if=/dev/zero of=$tmpnam bs=1024 count=4096 >/dev/null 2>&1
+}
+
+conffile() {
+	echo ${confdata} >${conffile}
+}

Reply to: