Hello community, here is the log from the commit of package nbd for openSUSE:Factory checked in at 2012-05-22 08:16:56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/nbd (Old) and /work/SRC/openSUSE:Factory/.nbd.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "nbd", Maintainer is "[email protected]" Changes: -------- --- /work/SRC/openSUSE:Factory/nbd/nbd.changes 2012-03-01 17:21:19.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.nbd.new/nbd.changes 2012-05-22 08:16:58.000000000 +0200 @@ -1,0 +2,8 @@ +Fri May 18 13:44:05 UTC 2012 - [email protected] + +- Update to nbd-3.1 + * minor bug fixes + * new feature: ability for the client to list the exports a server + supports + +------------------------------------------------------------------- Old: ---- nbd-3.0.tar.bz2 New: ---- nbd-3.1.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ nbd.spec ++++++ --- /var/tmp/diff_new_pack.y74Ox1/_old 2012-05-22 08:16:59.000000000 +0200 +++ /var/tmp/diff_new_pack.y74Ox1/_new 2012-05-22 08:16:59.000000000 +0200 @@ -15,22 +15,20 @@ # Please submit bugfixes or comments via http://bugs.opensuse.org/ # -# norootforbuild - Name: nbd -BuildRequires: doxygen glib2-devel >= 2.26.0 +BuildRequires: doxygen +BuildRequires: glib2-devel >= 2.26.0 PreReq: %insserv_prereq coreutils -Version: 3.0 -Release: 1 -License: GPL-2.0+ -Group: Productivity/Networking/Other -AutoReqProv: on +Version: 3.1 +Release: 0 Source: %{name}-%{version}.tar.bz2 Source2: init.nbd-server Patch2: nbd-2.9.25-close.diff Patch3: nbd-2.9.25-doxyfile.diff Summary: Network Block Device Server and Client Utilities +License: GPL-2.0+ +Group: Productivity/Networking/Other Url: http://nbd.sourceforge.net/ Prefix: /usr BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -64,7 +62,6 @@ Paul Clements <[email protected]> %package doc -License: GPL-2.0+ Summary: Network Block Device Server and Client Utilities Group: Productivity/Networking/Other Requires: nbd = %{version} ++++++ nbd-3.0.tar.bz2 -> nbd-3.1.tar.bz2 ++++++ ++++ 2637 lines of diff (skipped) ++++ retrying with extended exclude list diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/nbd-3.0/README new/nbd-3.1/README --- old/nbd-3.0/README 2011-10-01 12:28:58.000000000 +0200 +++ new/nbd-3.1/README 2012-05-13 17:15:38.000000000 +0200 @@ -9,8 +9,8 @@ nbd-server and nbd-client on the same machine, you may run into some deadlock issues if you do that[1]. -To install the package, please see the INSTALL file. You'll need to -install it on both the client and the server. +To install the package, do the normal configure/make/make install dance. +You'll need to install it on both the client and the server. Using NBD is quite easy. First, on the client, you need to create the device nodes: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/nbd-3.0/cliserv.h new/nbd-3.1/cliserv.h --- old/nbd-3.0/cliserv.h 2011-10-01 12:28:58.000000000 +0200 +++ new/nbd-3.1/cliserv.h 2012-05-13 17:15:38.000000000 +0200 @@ -56,6 +56,7 @@ u64 cliserv_magic = 0x00420281861253LL; u64 opts_magic = 0x49484156454F5054LL; +u64 rep_magic = 0x3e889045565a9LL; #define INIT_PASSWD "NBDMAGIC" #define INFO(a) do { } while(0) @@ -148,4 +149,20 @@ * served */ /* Options that the client can select to the server */ -#define NBD_OPT_EXPORT_NAME (1 << 0) /* Client wants to select a named export (is followed by length and name of export) */ +#define NBD_OPT_EXPORT_NAME (1) /** Client wants to select a named export (is followed by name of export) */ +#define NBD_OPT_ABORT (2) /** Client wishes to abort negotiation */ +#define NBD_OPT_LIST (3) /** Client request list of supported exports (not followed by data) */ + +/* Replies the server can send during negotiation */ +#define NBD_REP_ACK (1) /** ACK a request. Data: option number to be acked */ +#define NBD_REP_SERVER (2) /** Reply to NBD_OPT_LIST (one of these per server; must be followed by NBD_REP_ACK to signal the end of the list */ +#define NBD_REP_FLAG_ERROR (1 << 31) /** If the high bit is set, the reply is an error */ +#define NBD_REP_ERR_UNSUP (1 | NBD_REP_FLAG_ERROR) /** Client requested an option not understood by this version of the server */ +#define NBD_REP_ERR_POLICY (2 | NBD_REP_FLAG_ERROR) /** Client requested an option not allowed by server configuration. (e.g., the option was disabled) */ +#define NBD_REP_ERR_INVALID (3 | NBD_REP_FLAG_ERROR) /** Client issued an invalid request */ +#define NBD_REP_ERR_PLATFORM (4 | NBD_REP_FLAG_ERROR) /** Option not supported on this platform */ + +/* Global flags */ +#define NBD_FLAG_FIXED_NEWSTYLE (1 << 0) /* new-style export that actually supports extending */ +/* Flags from client to server. Only one such option currently. */ +#define NBD_FLAG_C_FIXED_NEWSTYLE NBD_FLAG_FIXED_NEWSTYLE diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/nbd-3.0/configure.ac new/nbd-3.1/configure.ac --- old/nbd-3.0/configure.ac 2012-02-21 11:04:29.000000000 +0100 +++ new/nbd-3.1/configure.ac 2012-05-15 09:43:33.000000000 +0200 @@ -1,7 +1,7 @@ dnl Configure script for NBD system dnl (c) 1998 Martin Mares <[email protected]>, (c) 2000 Pavel Machek <[email protected]>, dnl (c) 2003-2006 Wouter Verhelst <[email protected]> -AC_INIT([nbd],[3.0],[[email protected]]) +AC_INIT([nbd],[3.1],[[email protected]]) AM_INIT_AUTOMAKE(foreign dist-bzip2) AM_MAINTAINER_MODE diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/nbd-3.0/man/nbd-client.8.in.sgml new/nbd-3.1/man/nbd-client.8.in.sgml --- old/nbd-3.0/man/nbd-client.8.in.sgml 2011-10-01 12:28:58.000000000 +0200 +++ new/nbd-3.1/man/nbd-client.8.in.sgml 2012-05-15 09:55:51.000000000 +0200 @@ -74,6 +74,10 @@ <command>&dhpackage;</command> <arg choice="plain"><option>-c <replaceable>nbd-device</replaceable></option></arg> </cmdsynopsis> + <cmdsynopsis> + <command>&dhpackage;</command> + <arg choice="plain"><option>-l <replaceable>host</replaceable></option></arg> + </cmdsynopsis> </refsynopsisdiv> <refsect1> <title>DESCRIPTION</title> @@ -167,6 +171,22 @@ </listitem> </varlistentry> <varlistentry> + <term><option>-list</option></term> + <term><option>-l</option></term> + <listitem> + <para> + Ask the server for a list of available exports. If the + server is exporting over IPv6 as well as over IPv4, this + will list all exports twice; otherwise, it should list them + all only once.</para> + <para>Note that this option <emph>only</emph> works + with nbd-server processes running version 3.1 or above, and + must be enabled in server configuration (with the + "allowlist" option) before it can be used. + </para> + </listitem> + </varlistentry> + <varlistentry> <term><option>-persist</option></term> <term><option>-p</option></term> <listitem> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/nbd-3.0/man/nbd-client.8.sh.in new/nbd-3.1/man/nbd-client.8.sh.in --- old/nbd-3.0/man/nbd-client.8.sh.in 2011-10-01 12:31:44.000000000 +0200 +++ new/nbd-3.1/man/nbd-client.8.sh.in 2012-05-15 09:57:47.000000000 +0200 @@ -10,7 +10,7 @@ .\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> .\" Please send any bug reports, improvements, comments, patches, .\" etc. to Steve Cheng <[email protected]>. -.TH "NBD-CLIENT" "8" "01 October 2011" "" "" +.TH "NBD-CLIENT" "8" "$Date$" "" "" .SH NAME nbd-client \- connect to a server running nbd-server(1), to use its exported block device @@ -24,6 +24,9 @@ \fBnbd-client\fR \fB-c \fInbd-device\fB\fR + +\fBnbd-client\fR \fB-l \fIhost\fB\fR + .SH "DESCRIPTION" .PP With \fBnbd-client\fR, you can connect to a @@ -97,6 +100,19 @@ Disconnect the specified nbd device from the server .TP +\fB-list\fR +.TP +\fB-l\fR +Ask the server for a list of available exports. If the +server is exporting over IPv6 as well as over IPv4, this +will list all exports twice; otherwise, it should list them +all only once. + +Note that this option only works +with nbd-server processes running version 3.1 or above, and +must be enabled in server configuration (with the +"allowlist" option) before it can be used. +.TP \fB-persist\fR .TP \fB-p\fR diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/nbd-3.0/man/nbd-server.5.in.sgml new/nbd-3.1/man/nbd-server.5.in.sgml --- old/nbd-3.0/man/nbd-server.5.in.sgml 2011-11-29 08:54:43.000000000 +0100 +++ new/nbd-3.1/man/nbd-server.5.in.sgml 2012-05-15 09:57:45.000000000 +0200 @@ -110,6 +110,18 @@ <!-- These are in alphabetical order, please keep it that way --> <variablelist> <varlistentry> + <term><option>allowlist</option></term> + <listitem> + <para> + Optional; boolean + </para> + <para> + Whether to allow the client to fetch a list of exports from + this server. If enabled, the client can run + <command>nbd-client -l</command> to get a list of exports + on this server. + </para> + <varlistentry> <term><option>group</option></term> <listitem> <para> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/nbd-3.0/man/nbd-server.5.sh.in new/nbd-3.1/man/nbd-server.5.sh.in --- old/nbd-3.0/man/nbd-server.5.sh.in 2011-11-29 08:58:20.000000000 +0100 +++ new/nbd-3.1/man/nbd-server.5.sh.in 2012-05-15 09:57:47.000000000 +0200 @@ -10,7 +10,7 @@ .\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> .\" Please send any bug reports, improvements, comments, patches, .\" etc. to Steve Cheng <[email protected]>. -.TH "NBD-SERVER" "5" "29 November 2011" "" "" +.TH "NBD-SERVER" "5" "$Date: 2006-10-18 15:01:57 +0200 (wo, 18 okt 2006) $" "" "" .SH NAME $sysconfdir/nbd-server/config \- configuration file for nbd-server @@ -59,6 +59,14 @@ leading whitespace is stripped (but trailing whitespace is not). .SH "OPTIONS FOR SECTION [GENERIC]" .TP +\fBallowlist\fR +Optional; boolean + +Whether to allow the client to fetch a list of exports from +this server. If enabled, the client can run +\fBnbd-client -l\fR to get a list of exports +on this server. +.TP \fBgroup\fR Optional; string. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/nbd-3.0/nbd-client.c new/nbd-3.1/nbd-client.c --- old/nbd-3.0/nbd-client.c 2012-02-21 11:03:32.000000000 +0100 +++ new/nbd-3.1/nbd-client.c 2012-05-13 17:15:38.000000000 +0200 @@ -46,14 +46,16 @@ #include <sdp_inet.h> #endif +#define NBDC_DO_LIST 1 + int check_conn(char* devname, int do_print) { char buf[256]; char* p; int fd; int len; - if(!strncmp(devname, "/dev/", 5)) { - devname+=5; + if( (p=strrchr(devname, '/')) ) { + devname=p+1; } if((p=strchr(devname, 'p'))) { /* We can't do checks on partitions. */ @@ -124,7 +126,96 @@ return sock; } -void negotiate(int sock, u64 *rsize64, u32 *flags, char* name) { +void ask_list(int sock) { + uint32_t opt; + uint32_t opt_server; + uint32_t len; + uint32_t reptype; + uint64_t magic; + char buf[1024]; + + magic = ntohll(opts_magic); + if (write(sock, &magic, sizeof(magic)) < 0) + err("Failed/2.2: %m"); + + /* Ask for the list */ + opt = htonl(NBD_OPT_LIST); + if(write(sock, &opt, sizeof(opt)) < 0) { + err("writing list option failed: %m"); + } + /* Send the length (zero) */ + len = htonl(0); + if(write(sock, &len, sizeof(len)) < 0) { + err("writing length failed: %m"); + } + /* newline, move away from the "Negotiation:" line */ + printf("\n"); + do { + memset(buf, 0, 1024); + if(read(sock, &magic, sizeof(magic)) < 0) { + err("Reading magic from server: %m"); + } + if(read(sock, &opt_server, sizeof(opt_server)) < 0) { + err("Reading option: %m"); + } + if(read(sock, &reptype, sizeof(reptype)) <0) { + err("Reading reply from server: %m"); + } + if(read(sock, &len, sizeof(len)) < 0) { + err("Reading length from server: %m"); + } + magic=ntohll(magic); + len=ntohl(len); + reptype=ntohl(reptype); + if(magic != rep_magic) { + err("Not enough magic from server"); + } + if(reptype & NBD_REP_FLAG_ERROR) { + switch(reptype) { + case NBD_REP_ERR_POLICY: + fprintf(stderr, "\nE: listing not allowed by server.\n"); + break; + default: + fprintf(stderr, "\nE: unexpected error from server.\n"); + break; + } + if(len) { + if(read(sock, buf, len) < 0) { + fprintf(stderr, "\nE: could not read error message from server\n"); + } + fprintf(stderr, "Server said: %s\n", buf); + } + exit(EXIT_FAILURE); + } else { + if(len) { + if(reptype != NBD_REP_SERVER) { + err("Server sent us a reply we don't understand!"); + } + if(read(sock, &len, sizeof(len)) < 0) { + fprintf(stderr, "\nE: could not read export name length from server\n"); + exit(EXIT_FAILURE); + } + len=ntohl(len); + if(read(sock, buf, len) < 0) { + fprintf(stderr, "\nE: could not read export name from server\n"); + exit(EXIT_FAILURE); + } + printf("%s\n", buf); + } + } + } while(reptype != NBD_REP_ACK); + opt=htonl(NBD_OPT_ABORT); + len=htonl(0); + magic=htonll(opts_magic); + if (write(sock, &magic, sizeof(magic)) < 0) + err("Failed/2.2: %m"); + if (write(sock, &opt, sizeof(opt)) < 0) + err("Failed writing abort"); + if (write(sock, &len, sizeof(len)) < 0) + err("Failed writing length"); +} + +void negotiate(int sock, u64 *rsize64, u32 *flags, char* name, uint32_t needed_flags, uint32_t client_flags, uint32_t do_opts) { u64 magic, size64; uint16_t tmp; char buf[256] = "\0\0\0\0\0\0\0\0\0"; @@ -143,7 +234,6 @@ if(name) { uint32_t opt; uint32_t namesize; - uint32_t reserved = 0; if (magic != opts_magic) err("Not enough opts_magic"); @@ -152,15 +242,28 @@ err("Failed reading flags: %m"); } *flags = ((u32)ntohs(tmp)); + if((needed_flags & *flags) != needed_flags) { + /* There's currently really only one reason why this + * check could possibly fail, but we may need to change + * this error message in the future... */ + fprintf(stderr, "\nE: Server does not support listing exports\n"); + exit(EXIT_FAILURE); + } - /* reserved for future use*/ - if (write(sock, &reserved, sizeof(reserved)) < 0) + client_flags = htonl(client_flags); + if (write(sock, &client_flags, sizeof(client_flags)) < 0) err("Failed/2.1: %m"); + if(do_opts & NBDC_DO_LIST) { + ask_list(sock); + exit(EXIT_SUCCESS); + } + /* Write the export name that we're after */ - magic = ntohll(opts_magic); + magic = htonll(opts_magic); if (write(sock, &magic, sizeof(magic)) < 0) err("Failed/2.2: %m"); + opt = ntohl(NBD_OPT_EXPORT_NAME); if (write(sock, &opt, sizeof(opt)) < 0) err("Failed/2.3: %m"); @@ -273,7 +376,7 @@ va_list ap; va_start(ap, errmsg); snprintf(tmp, 256, "ERROR: %s\n\n", errmsg); - vfprintf(stderr, errmsg, ap); + vfprintf(stderr, tmp, ap); va_end(ap); } else { fprintf(stderr, "nbd-client version %s\n", PACKAGE_VERSION); @@ -283,6 +386,7 @@ fprintf(stderr, "Or : nbd-client -d nbd_device\n"); fprintf(stderr, "Or : nbd-client -c nbd_device\n"); fprintf(stderr, "Or : nbd-client -h|--help\n"); + fprintf(stderr, "Or : nbd-client -l|--list host\n"); fprintf(stderr, "Default value for blocksize is 1024 (recommended for ethernet)\n"); fprintf(stderr, "Allowed values for blocksize are 512,1024,2048,4096\n"); /* will be checked in kernel :) */ fprintf(stderr, "Note, that kernel 2.4.2 and older ones do not work correctly with\n"); @@ -328,11 +432,15 @@ int c; int nonspecial=0; char* name=NULL; + uint32_t needed_flags; + uint32_t cflags; + uint32_t opts; struct option long_options[] = { { "block-size", required_argument, NULL, 'b' }, { "check", required_argument, NULL, 'c' }, { "disconnect", required_argument, NULL, 'd' }, { "help", no_argument, NULL, 'h' }, + { "list", no_argument, NULL, 'l' }, { "name", required_argument, NULL, 'N' }, { "nofork", no_argument, NULL, 'n' }, { "persist", no_argument, NULL, 'p' }, @@ -344,7 +452,7 @@ logging(); - while((c=getopt_long_only(argc, argv, "-b:c:d:hnN:pSst:", long_options, NULL))>=0) { + while((c=getopt_long_only(argc, argv, "-b:c:d:hlnN:pSst:", long_options, NULL))>=0) { switch(c) { case 1: // non-option argument @@ -399,6 +507,14 @@ case 'h': usage(NULL); exit(EXIT_SUCCESS); + case 'l': + needed_flags |= NBD_FLAG_FIXED_NEWSTYLE; + cflags |= NBD_FLAG_C_FIXED_NEWSTYLE; + opts |= NBDC_DO_LIST; + name=""; + nbddev=""; + port = NBD_DEFAULT_PORT; + break; case 'n': nofork=1; break; @@ -432,13 +548,14 @@ exit(EXIT_FAILURE); } + sock = opennet(hostname, port, sdp); + + negotiate(sock, &size64, &flags, name, needed_flags, cflags, opts); + nbd = open(nbddev, O_RDWR); if (nbd < 0) err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded."); - sock = opennet(hostname, port, sdp); - - negotiate(sock, &size64, &flags, name); setsizes(nbd, size64, blocksize, flags); set_timeout(nbd, timeout); finish_sock(sock, nbd, swap); @@ -474,8 +591,9 @@ #endif if (ioctl(nbd, NBD_DO_IT) < 0) { - fprintf(stderr, "Kernel call returned: %m"); - if(errno==EBADR) { + int error = errno; + fprintf(stderr, "nbd,%d: Kernel call returned: %d", getpid(), error); + if(error==EBADR) { /* The user probably did 'nbd-client -d' on us. * quit */ cont=0; @@ -488,7 +606,7 @@ close(sock); close(nbd); sock = opennet(hostname, port, sdp); nbd = open(nbddev, O_RDWR); - negotiate(sock, &new_size, &new_flags, name); + negotiate(sock, &new_size, &new_flags, name, needed_flags, cflags, opts); if (size64 != new_size) { err("Size of the device changed. Bye"); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/nbd-3.0/nbd-server.c new/nbd-3.1/nbd-server.c --- old/nbd-3.0/nbd-server.c 2012-02-21 11:04:29.000000000 +0100 +++ new/nbd-3.1/nbd-server.c 2012-05-13 17:15:38.000000000 +0200 @@ -59,6 +59,7 @@ * headers, so must come before those */ #include "lfs.h" +#include <assert.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/stat.h> @@ -118,8 +119,8 @@ gchar* runuser=NULL; /** What group we're running as */ gchar* rungroup=NULL; -/** whether to export using the old negotiation protocol (port-based) */ -gboolean do_oldstyle=FALSE; +/** global flags */ +int glob_flags=0; /* Whether we should avoid forking */ int dontfork = 0; @@ -154,6 +155,8 @@ authorization file (yuck) */ #define BUFSIZE ((1024*1024)+sizeof(struct nbd_reply)) /**< Size of buffer that can hold requests */ #define DIFFPAGESIZE 4096 /**< diff file uses those chunks */ + +/** Per-export flags: */ #define F_READONLY 1 /**< flag to tell us a file is readonly */ #define F_MULTIFILE 2 /**< flag to tell us a file is exported using -m */ #define F_COPYONWRITE 4 /**< flag to tell us a file is exported using @@ -167,6 +170,11 @@ #define F_ROTATIONAL 512 /**< Whether server wants the client to implement the elevator algorithm */ #define F_TEMPORARY 1024 /**< Whether the backing file is temporary and should be created then unlinked */ #define F_TRIM 2048 /**< Whether server wants TRIM (discard) to be sent by the client */ +#define F_FIXED 4096 /**< Client supports fixed new-style protocol (and can thus send us extra options */ + +/** Global flags: */ +#define F_OLDSTYLE 1 /**< Allow oldstyle (port-based) exports */ +#define F_LIST 2 /**< Allow clients to list the exports on a server */ GHashTable *children; char pidfname[256]; /**< name of our PID file */ char pidftemplate[256]; /**< template to be used for the filename of the PID file */ @@ -248,6 +256,7 @@ u32 *difmap; /**< see comment on the global difmap for this one */ gboolean modern; /**< client was negotiated using modern negotiation protocol */ int transactionlogfd;/**< fd for transaction log */ + int clientfeats; /**< Features supported by this client */ } CLIENT; /** @@ -588,7 +597,7 @@ g_free(serve); serve=NULL; } else { - do_oldstyle = TRUE; + glob_flags |= F_OLDSTYLE; } if(do_output) { if(!serve) { @@ -768,6 +777,7 @@ gchar* fname; GArray* retval = NULL; GArray* tmp; + struct stat stbuf; if(!dir) { g_set_error(e, errdomain, CFILE_DIR_UNKNOWN, "Invalid directory specified: %s", strerror(errno)); @@ -776,13 +786,24 @@ errno=0; while((de = readdir(dirh))) { int saved_errno=errno; + fname = g_build_filename(dir, de->d_name, NULL); switch(de->d_type) { + case DT_UNKNOWN: + /* Filesystem doesn't return type of + * file through readdir. Run stat() on + * the file instead */ + if(stat(fname, &stbuf)) { + perror("stat"); + goto err_out; + } + if (!S_ISREG(stbuf.st_mode)) { + goto next; + } case DT_REG: /* Skip unless the name ends with '.conf' */ if(strcmp((de->d_name + strlen(de->d_name) - 5), ".conf")) { continue; } - fname = g_build_filename(dir, de->d_name, NULL); tmp = parse_cfile(fname, FALSE, e); errno=saved_errno; if(*e) { @@ -792,10 +813,11 @@ retval = g_array_new(FALSE, TRUE, sizeof(SERVER)); retval = g_array_append_vals(retval, tmp->data, tmp->len); g_array_free(tmp, TRUE); - g_free(fname); default: break; } + next: + g_free(fname); } if(errno) { g_set_error(e, errdomain, CFILE_READDIR_ERR, "Error trying to read directory: %s", strerror(errno)); @@ -850,10 +872,11 @@ PARAM gp[] = { { "user", FALSE, PARAM_STRING, &runuser, 0 }, { "group", FALSE, PARAM_STRING, &rungroup, 0 }, - { "oldstyle", FALSE, PARAM_BOOL, &do_oldstyle, 1 }, + { "oldstyle", FALSE, PARAM_BOOL, &glob_flags, F_OLDSTYLE }, { "listenaddr", FALSE, PARAM_STRING, &modern_listen, 0 }, { "port", FALSE, PARAM_STRING, &modernport, 0 }, { "includedir", FALSE, PARAM_STRING, &cfdir, 0 }, + { "allowlist", FALSE, PARAM_BOOL, &glob_flags, F_LIST }, }; PARAM* p=gp; int p_size=sizeof(gp)/sizeof(PARAM); @@ -895,13 +918,13 @@ if(i==1 || !have_global) { p=lp; p_size=lp_size; - if(!do_oldstyle) { + if(!(glob_flags & F_OLDSTYLE)) { lp[1].required = FALSE; } } for(j=0;j<p_size;j++) { - g_assert(p[j].target != NULL); - g_assert(p[j].ptype==PARAM_INT||p[j].ptype==PARAM_STRING||p[j].ptype==PARAM_BOOL||p[j].ptype==PARAM_INT64); + assert(p[j].target != NULL); + assert(p[j].ptype==PARAM_INT||p[j].ptype==PARAM_STRING||p[j].ptype==PARAM_BOOL||p[j].ptype==PARAM_INT64); switch(p[j].ptype) { case PARAM_INT: ival = g_key_file_get_integer(cfile, @@ -987,7 +1010,7 @@ } else { s.virtstyle=VIRT_IPLIT; } - if(s.port && !do_oldstyle) { + if(s.port && !(glob_flags & F_OLDSTYLE)) { g_warning("A port was specified, but oldstyle exports were not requested. This may not do what you expect."); g_warning("Please read 'man 5 nbd-server' and search for oldstyle for more info"); } @@ -1168,7 +1191,7 @@ } /* end should never go negative, since first startoff is 0 and a >= 0 */ - g_assert(end >= 0); + assert(end >= 0); fi = g_array_index(export, FILE_INFO, end); *fhandle = fi.fhandle; @@ -1485,6 +1508,77 @@ return 0; } +static void send_reply(uint32_t opt, int net, uint32_t reply_type, size_t datasize, void* data) { + uint64_t magic = htonll(0x3e889045565a9LL); + reply_type = htonl(reply_type); + uint32_t datsize = htonl(datasize); + struct iovec v_data[] = { + { &magic, sizeof(magic) }, + { &opt, sizeof(opt) }, + { &reply_type, sizeof(reply_type) }, + { &datsize, sizeof(datsize) }, + { data, datasize }, + }; + writev(net, v_data, 5); +} + +static CLIENT* handle_export_name(uint32_t opt, int net, GArray* servers, uint32_t cflags) { + uint32_t namelen; + char* name; + int i; + + if (read(net, &namelen, sizeof(namelen)) < 0) + err("Negotiation failed/7: %m"); + namelen = ntohl(namelen); + name = malloc(namelen+1); + name[namelen]=0; + if (read(net, name, namelen) < 0) + err("Negotiation failed/8: %m"); + for(i=0; i<servers->len; i++) { + SERVER* serve = &(g_array_index(servers, SERVER, i)); + if(!strcmp(serve->servename, name)) { + CLIENT* client = g_new0(CLIENT, 1); + client->server = serve; + client->exportsize = OFFT_MAX; + client->net = net; + client->modern = TRUE; + client->transactionlogfd = -1; + client->clientfeats = cflags; + free(name); + return client; + } + } + free(name); + return NULL; +} + +static void handle_list(uint32_t opt, int net, GArray* servers, uint32_t cflags) { + uint32_t len; + int i; + char buf[1024]; + char *ptr = buf + sizeof(len); + + if (read(net, &len, sizeof(len)) < 0) + err("Negotiation failed/8: %m"); + len = ntohl(len); + if(len) { + send_reply(opt, net, NBD_REP_ERR_INVALID, 0, NULL); + } + if(!(glob_flags & F_LIST)) { + send_reply(opt, net, NBD_REP_ERR_POLICY, 0, NULL); + err_nonfatal("Client tried disallowed list option"); + return; + } + for(i=0; i<servers->len; i++) { + SERVER* serve = &(g_array_index(servers, SERVER, i)); + len = htonl(strlen(serve->servename)); + memcpy(buf, &len, sizeof(len)); + strcpy(ptr, serve->servename); + send_reply(opt, net, NBD_REP_SERVER, strlen(serve->servename)+sizeof(len), buf); + } + send_reply(opt, net, NBD_REP_ACK, 0, NULL); +} + /** * Do the initial negotiation. * @@ -1498,7 +1592,10 @@ uint64_t magic; memset(zeros, '\0', sizeof(zeros)); - g_assert(((phase & NEG_INIT) && (phase & NEG_MODERN)) || client); + assert(((phase & NEG_INIT) && (phase & NEG_MODERN)) || client); + if(phase & NEG_MODERN) { + smallflags |= NBD_FLAG_FIXED_NEWSTYLE; + } if(phase & NEG_INIT) { /* common */ if (write(net, INIT_PASSWD, 8) < 0) { @@ -1521,54 +1618,50 @@ } if ((phase & NEG_MODERN) && (phase & NEG_INIT)) { /* modern */ - uint32_t reserved; + uint32_t cflags; uint32_t opt; - uint32_t namelen; - char* name; - int i; if(!servers) err("programmer error"); + smallflags = htons(smallflags); if (write(net, &smallflags, sizeof(uint16_t)) < 0) - err("Negotiation failed/3: %m"); - if (read(net, &reserved, sizeof(reserved)) < 0) - err("Negotiation failed/4: %m"); - if (read(net, &magic, sizeof(magic)) < 0) - err("Negotiation failed/5: %m"); - magic = ntohll(magic); - if(magic != opts_magic) { - close(net); - return NULL; - } - if (read(net, &opt, sizeof(opt)) < 0) - err("Negotiation failed/6: %m"); - opt = ntohl(opt); - if(opt != NBD_OPT_EXPORT_NAME) { + err_nonfatal("Negotiation failed/3: %m"); + if (read(net, &cflags, sizeof(cflags)) < 0) + err_nonfatal("Negotiation failed/4: %m"); + cflags = htonl(cflags); + do { + if (read(net, &magic, sizeof(magic)) < 0) + err_nonfatal("Negotiation failed/5: %m"); + magic = ntohll(magic); + if(magic != opts_magic) { + close(net); + return NULL; + } + if (read(net, &opt, sizeof(opt)) < 0) + err_nonfatal("Negotiation failed/6: %m"); + opt = ntohl(opt); + switch(opt) { + case NBD_OPT_EXPORT_NAME: + // NBD_OPT_EXPORT_NAME must be the last + // selected option, so return from here + // if that is chosen. + return handle_export_name(opt, net, servers, cflags); + break; + case NBD_OPT_LIST: + handle_list(opt, net, servers, cflags); + break; + case NBD_OPT_ABORT: + // handled below + break; + default: + send_reply(opt, net, NBD_REP_ERR_UNSUP, 0, NULL); + break; + } + } while((opt != NBD_OPT_EXPORT_NAME) && (opt != NBD_OPT_ABORT)); + if(opt == NBD_OPT_ABORT) { close(net); return NULL; } - if (read(net, &namelen, sizeof(namelen)) < 0) - err("Negotiation failed/7: %m"); - namelen = ntohl(namelen); - name = malloc(namelen+1); - name[namelen]=0; - if (read(net, name, namelen) < 0) - err("Negotiation failed/8: %m"); - for(i=0; i<servers->len; i++) { - SERVER* serve = &(g_array_index(servers, SERVER, i)); - if(!strcmp(serve->servename, name)) { - CLIENT* client = g_new0(CLIENT, 1); - client->server = serve; - client->exportsize = OFFT_MAX; - client->net = net; - client->modern = TRUE; - client->transactionlogfd = -1; - free(name); - return client; - } - } - free(name); - return NULL; } /* common */ size_host = htonll((u64)(client->exportsize)); @@ -1852,11 +1945,11 @@ /* If we created the file, it will be length zero */ if (!lastsize && cancreate) { - /* we can ignore errors as we recalculate the size */ - ftruncate (fi.fhandle, client->server->expected_size); - lastsize = size_autodetect(fi.fhandle); - if (lastsize != client->server->expected_size) - err("Could not expand file"); + assert(!multifile); + if(ftruncate (fi.fhandle, client->server->expected_size)<0) { + err("Could not expand file: %m"); + } + lastsize = client->server->expected_size; break; /* don't look for any more files */ } @@ -2233,7 +2326,7 @@ gchar *port = NULL; int e; - if(!do_oldstyle) { + if(!(glob_flags & F_OLDSTYLE)) { return serve->servename ? 1 : 0; } memset(&hints,'\0',sizeof(hints)); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/nbd-3.0/nbd-tester-client.c new/nbd-3.1/nbd-tester-client.c --- old/nbd-3.0/nbd-tester-client.c 2011-10-01 12:28:58.000000000 +0200 +++ new/nbd-3.1/nbd-tester-client.c 2012-05-13 17:15:42.000000000 +0200 @@ -605,7 +605,7 @@ goto err_open; } } - printf("%d: Requests(+): %d\n", (int)mypid, ++requests); + printf("%d: Requests(+): %d\r", (int)mypid, ++requests); if (sendflush) { long long int j = i ^ (1LL<<63); req.type = htonl(NBD_CMD_FLUSH); @@ -615,7 +615,7 @@ retval=-1; goto err_open; } - printf("%d: Requests(+): %d\n", (int)mypid, ++requests); + printf("%d: Requests(+): %d\r", (int)mypid, ++requests); } } do { @@ -631,7 +631,7 @@ retval=-1; goto err_open; } - printf("%d: Requests(-): %d\n", (int)mypid, --requests); + printf("%d: Requests(-): %d\r", (int)mypid, --requests); } } while FD_ISSET(sock, &set); /* Now wait until we can write again or until a second have @@ -659,9 +659,10 @@ /* Okay, there's something ready for * reading here */ read_packet_check_header(sock, (testflags & TEST_WRITE)?0:1024, i); - printf("%d: Requests(-): %d\n", (int)mypid, --requests); + printf("%d: Requests(-): %d\r", (int)mypid, --requests); } } while (requests); + printf("\n"); if(gettimeofday(&stop, NULL)<0) { retval=-1; snprintf(errstr, errstr_len, "Could not measure end time: %s", strerror(errno)); @@ -714,8 +715,8 @@ } static inline int checkbuf(char *buf, uint64_t seq, uint64_t blknum) { - char cmp[512]; - makebuf(cmp, seq, blknum); + uint64_t cmp[64]; // 512/8 = 64 + makebuf((char *)cmp, seq, blknum); return memcmp(cmp, buf, 512)?-1:0; } @@ -1100,13 +1101,15 @@ goto err_open; } - prc = g_hash_table_lookup(handlehash, rep.handle); + uint64_t handle; + memcpy(&handle,rep.handle,8); + prc = g_hash_table_lookup(handlehash, &handle); if (!prc) { retval=-1; snprintf(errstr, errstr_len, "Unrecognised handle in reply: 0x%llX", *(long long unsigned int*)(rep.handle)); goto err_open; } - if (!g_hash_table_remove(handlehash, rep.handle)) { + if (!g_hash_table_remove(handlehash, &handle)) { retval=-1; snprintf(errstr, errstr_len, "Could not remove handle from hash: 0x%llX", *(long long unsigned int*)(rep.handle)); goto err_open; @@ -1185,7 +1188,7 @@ } if (!(printer++ % 1000) || !(readtransactionfile || txqueue.numitems || inflight.numitems) ) - printf("%d: Seq %08lld Queued: %08d Inflight: %08d Done: %08lld\n", + printf("%d: Seq %08lld Queued: %08d Inflight: %08d Done: %08lld\r", (int)mypid, (long long int) seq, txqueue.numitems, @@ -1194,6 +1197,8 @@ } + printf("\n"); + if (gettimeofday(&stop, NULL)<0) { retval=-1; snprintf(errstr, errstr_len, "Could not measure end time: %s", strerror(errno)); -- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
