--- /dev/null
+/*
+ * Open connection for network block device
+ *
+ * Copyright 1997,1998 Pavel Machek, distribute under GPL
+ * <pavel@atrey.karlin.mff.cuni.cz>
+ *
+ * Version 1.0 - 64bit issues should be fixed, now
+ */
+
+/* I added new option '-d' to send the disconnect request */
+
+#include <asm/page.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h> /* sockaddr_in, htons, in_addr */
+#include <netdb.h> /* hostent, gethostby*, getservby* */
+#include <stdio.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <stdlib.h>
+
+#define MY_NAME "nbd_client"
+#ifndef __GNUC__
+#error I need GCC to work
+#endif
+
+#include <linux/ioctl.h>
+#include "cliserv.h"
+
+int opennet(char *name, int port)
+{
+ int sock;
+ struct sockaddr_in xaddrin;
+ int xaddrinlen = sizeof(xaddrin);
+ struct hostent *hostn;
+
+ hostn = gethostbyname(name);
+ if (!hostn)
+ err("Gethostname failed: %h\n");
+
+ if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
+ err("Socket failed: %m");
+
+ xaddrin.sin_family = AF_INET;
+ xaddrin.sin_port = htons(port);
+ xaddrin.sin_addr.s_addr = *((int *) hostn->h_addr);
+ if ((connect(sock, (struct sockaddr *) &xaddrin, xaddrinlen) < 0))
+ err("Connect: %m");
+
+ setmysockopt(sock);
+ return sock;
+}
+
+int main(int argc, char *argv[])
+{
+ int port, sock, nbd, one = 1;
+ u64 magic, size64;
+ unsigned long size;
+ char buf[256] = "\0\0\0\0\0\0\0\0\0";
+ int swap = (argc > 4);
+
+ logging();
+
+ if (argc < 2) {
+ errmsg:
+ fprintf(stderr, "Usage: host port nbd_device -swap\n");
+ fprintf(stderr, "or -d nbd_device \n");
+ return 1;
+ }
+
+ if (strcmp(argv[1],"-d")==0) {
+ nbd = open(argv[2], O_RDWR);
+ if (nbd < 0)
+ err("Can not open NBD: %m");
+ printf("Disconnecting: que, ");
+ if (ioctl(nbd, NBD_CLEAR_QUE)< 0)
+ err("Ioctl failed: %m\n");
+ printf("disconnect, ");
+#ifdef NBD_DISCONNECT
+ if (ioctl(nbd, NBD_DISCONNECT)<0)
+ err("Ioctl failed: %m\n");
+ printf("sock, ");
+#else
+ die("Can't disconnect: I was not compiled with disconnect support!\n" );
+#endif
+ if (ioctl(nbd, NBD_CLEAR_SOCK)<0)
+ err("Ioctl failed: %m\n");
+ printf("done\n");
+ return 0;
+ }
+
+ if (argc<4) goto errmsg;
+ port = atoi(argv[2]);
+ sock = opennet(argv[1], port);
+ nbd = open(argv[3], O_RDWR);
+ if (nbd < 0)
+ err("Can not open NBD: %m");
+
+ printf("Negotiation: ");
+ if (read(sock, buf, 8) < 0)
+ err("Failed/1: %m");
+ if (strcmp(buf, INIT_PASSWD))
+ err("INIT_PASSWD bad");
+ printf(".");
+ if (read(sock, &magic, sizeof(magic)) < 0)
+ err("Failed/2: %m");
+ magic = ntohll(magic);
+ if (magic != cliserv_magic)
+ err("Not enough cliserv_magic");
+ printf(".");
+
+ if (read(sock, &size64, sizeof(size64)) < 0)
+ err("Failed/3: %m\n");
+ size64 = ntohll(size64);
+ if (size64 > (~0UL >> 1)) {
+#ifdef NBD_SET_SIZE_BLOCKS
+ if ((size64 >> 10) > (~0UL >> 1)) {
+ printf("size = %luMB", (unsigned long)(size64>>20));
+ err("Exported device is too big for me. Get 64-bit machine :-(\n");
+ } else
+ printf("size = %luKB", (unsigned long)(size64>>10));
+#else
+ printf("size = %luKB", (unsigned long)(size64>>10));
+ err("Exported device is too big. Get 64-bit machine or newer kernel :-(\n");
+#endif
+ } else
+ printf("size = %lu", (unsigned long)(size64));
+
+ if (read(sock, &buf, 128) < 0)
+ err("Failed/4: %m\n");
+ printf("\n");
+
+ if (size64 > (~0UL >> 1)) {
+#ifdef NBD_SET_SIZE_BLOCKS
+ if ((size64 >> 10) > (~0UL >> 1))
+ /*
+ * If you really need NBDs larger than 2TB on 32-bit
+ * machines you can use blocksizes larger than 1kB
+ * - FIXME
+ */
+ err("Device too large.\n");
+ else {
+ int er;
+
+ if (ioctl(nbd, NBD_SET_BLKSIZE, 1UL << 10) < 0)
+ err("Ioctl/1.1a failed: %m\n");
+ size = (unsigned long)(size64 >> 10);
+ if ((er = ioctl(nbd, NBD_SET_SIZE_BLOCKS, size)) < 0)
+ err("Ioctl/1.1b failed: %m\n");
+ }
+#else
+ err("Device too large.\n");
+#endif
+ } else {
+ size = (unsigned long)size64;
+ if (ioctl(nbd, NBD_SET_SIZE, size) < 0)
+ err("Ioctl/1 failed: %m\n");
+ }
+ ioctl(nbd, NBD_CLEAR_SOCK);
+ if (ioctl(nbd, NBD_SET_SOCK, sock) < 0)
+ err("Ioctl/2 failed: %m\n");
+
+#ifndef SO_SWAPPING
+ if (swap)
+ err("You have to compile me on machine with swapping patch enabled in order to use it later.");
+#else
+ if (swap)
+ if (setsockopt(sock, SOL_SOCKET, SO_SWAPPING, &one, sizeof(int)) < 0)
+ err("Could not enable swapping: %m");
+#endif
+
+ /* Go daemon */
+
+ chdir("/");
+ if (fork())
+ exit(0);
+
+ if (ioctl(nbd, NBD_DO_IT) < 0)
+ fprintf(stderr, "Kernel call returned: %m");
+ else
+ fprintf(stderr, "Kernel call returned.");
+ printf("Closing: que, ");
+ ioctl(nbd, NBD_CLEAR_QUE);
+ printf("sock, ");
+ ioctl(nbd, NBD_CLEAR_SOCK);
+ printf("done\n");
+ return 0;
+}
--- /dev/null
+/*
+ * Network Block Device - server
+ *
+ * Copyright 1996-1998 Pavel Machek, distribute under GPL
+ * <pavel@atrey.karlin.mff.cuni.cz>
+ *
+ * Version 1.0 - hopefully 64-bit-clean
+ * Version 1.1 - merging enhancements from Josh Parsons, <josh@coombs.anu.edu.au>
+ * Version 1.2 - autodetect size of block devices, thanx to Peter T. Breuer" <ptb@it.uc3m.es>
+ * Version 1.5 - can compile on Unix systems that don't have 64 bit integer
+ * type, or don't have 64 bit file offsets by defining FS_32BIT
+ * in compile options for nbd-server *only*. This can be done
+ * with make FSCHOICE=-DFS_32BIT nbd-server. (I don't have the
+ * original autoconf input file, or I would make it a configure
+ * option.) Ken Yap <ken@nlc.net.au>.
+ */
+
+#define VERSION "1.5"
+#define GIGA (1*1024*1024*1024)
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h> /* sockaddr_in, htons, in_addr */
+#include <netdb.h> /* hostent, gethostby*, getservby* */
+#include <syslog.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <arpa/inet.h>
+#include <strings.h>
+
+#define _IO(a,b)
+// #define ISSERVER
+#define MY_NAME "nbd_server"
+
+/* Authorization file should contain lines with IP addresses of
+ clients authorized to use the server. If it does not exist,
+ access is permitted. */
+#define AUTH_FILE "nbd_server.allow"
+
+#include "cliserv.h"
+#undef _IO
+/* Deep magic: ioctl.h defines _IO macro (at least on linux) */
+
+
+/* Debugging macros, now nothing goes to syslog unless you say ISSERVER */
+#ifdef ISSERVER
+#define msg2(a,b) syslog(a,b)
+#define msg3(a,b,c) syslog(a,b,c)
+#define msg4(a,b,c,d) syslog(a,b,c,d)
+#else
+#define msg2(a,b) do { fprintf(stderr,b) ; fputs("\n",stderr) ; } while(0)
+#define msg3(a,b,c) do { fprintf(stderr,b,c); fputs("\n",stderr) ; } while(0)
+#define msg4(a,b,c,d) do { fprintf(stderr,b,c,d); fputs("\n",stderr) ; } while(0)
+#endif
+
+
+#include <sys/ioctl.h>
+#include <sys/mount.h> /* For BLKGETSIZE */
+
+#ifdef FS_32BIT
+typedef u32 fsoffset_t;
+#define htonll htonl
+#define ntohll ntohl
+#else
+typedef u64 fsoffset_t;
+#endif
+
+
+//#define DODBG
+#ifdef DODBG
+#define DEBUG( a ) printf( a )
+#define DEBUG2( a,b ) printf( a,b )
+#define DEBUG3( a,b,c ) printf( a,b,c )
+#else
+#define DEBUG( a )
+#define DEBUG2( a,b )
+#define DEBUG3( a,b,c )
+#endif
+
+#if defined(HAVE_LLSEEK) && !defined(sun)
+/* Solaris already has llseek defined in unistd.h */
+extern long long llseek(unsigned int, long long, unsigned int);
+#endif
+
+void serveconnection(int net) ;
+void set_peername(int net,char *clientname) ;
+
+#define LINELEN 256
+char difffilename[256] ;
+
+int authorized_client(char *name)
+/* 0 - authorization refused, 1 - OK
+ authorization file contains one line per machine, no wildcards
+*/
+{ FILE *f ;
+
+ char line[LINELEN] ;
+
+ if ((f=fopen(AUTH_FILE,"r"))==NULL)
+ { msg4(LOG_INFO,"Can't open authorization file %s (%s).",
+ AUTH_FILE,strerror(errno)) ;
+ return 1 ;
+ }
+
+ while (fgets(line,LINELEN,f)!=NULL) {
+ if (strncmp(line,name,strlen(name))==0) { fclose(f) ; return 1 ; }
+ }
+ fclose(f) ;
+ return 0 ;
+}
+
+
+inline void readit(int f, void *buf, int len)
+{
+ int res;
+ while (len > 0) {
+ DEBUG("*");
+ if ((res = read(f, buf, len)) <= 0)
+ err("Read failed: %m");
+ len -= res;
+ buf += res;
+ }
+}
+
+inline void writeit(int f, void *buf, int len)
+{
+ int res;
+ while (len > 0) {
+ DEBUG("+");
+ if ((res = write(f, buf, len)) <= 0)
+ err("Write failed: %m");
+ len -= res;
+ buf += res;
+ }
+}
+
+int port; /* Port I'm listening at */
+char *exportname; /* File I'm exporting */
+fsoffset_t exportsize = ~0, hunksize = ~0; /* ...and its length */
+int flags = 0;
+int export[1024];
+int difffile=-1 ;
+u32 difffilelen=0 ; /* number of pages in difffile */
+u32 *difmap=NULL ;
+char clientname[256] ;
+
+
+#define DIFFPAGESIZE 4096 /* diff file uses those chunks */
+
+#define F_READONLY 1
+#define F_MULTIFILE 2
+#define F_COPYONWRITE 4
+
+void cmdline(int argc, char *argv[])
+{
+ int i;
+
+ if (argc < 3) {
+ printf("This is nbd-server version " VERSION "\n");
+ printf("Usage: port file_to_export [size][kKmM] [-r] [-m] [-c]\n"
+ " -r read only\n"
+ " -m multiple file\n"
+ " -c copy on write\n"
+ " if port is set to 0, stdin is used (for running from inetd)\n"
+ " if file_to_export contains '%%s', it is substituted with IP\n"
+ " address of machine trying to connect\n" );
+ exit(0);
+ }
+ port = atoi(argv[1]);
+ for (i = 3; i < argc; i++) {
+ if (*argv[i] == '-') {
+ switch (argv[i][1]) {
+ case 'r':
+ flags |= F_READONLY;
+ break;
+ case 'm':
+ flags |= F_MULTIFILE;
+ hunksize = 1*GIGA;
+ break;
+ case 'c': flags |=F_COPYONWRITE ;
+ break ;
+ }
+ } else {
+ fsoffset_t es;
+ int last = strlen(argv[i])-1;
+ char suffix = argv[i][last];
+ if (suffix == 'k' || suffix == 'K' ||
+ suffix == 'm' || suffix == 'M')
+ argv[i][last] = '\0';
+ es = (fsoffset_t)atol(argv[i]);
+ switch (suffix) {
+ case 'm':
+ case 'M': es <<= 10;
+ case 'k':
+ case 'K': es <<= 10;
+ default : break;
+ }
+ exportsize = es;
+ }
+ }
+
+ exportname = argv[2];
+}
+
+void connectme(int port)
+{
+ struct sockaddr_in addrin;
+ int addrinlen = sizeof(addrin);
+ int net, sock, newpid;
+
+ if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
+ err("socket: %m");
+
+ DEBUG("Waiting for connections... bind, ");
+ addrin.sin_family = AF_INET;
+ addrin.sin_port = htons(port);
+ addrin.sin_addr.s_addr = 0;
+ if (bind(sock, (struct sockaddr *) &addrin, addrinlen) < 0)
+ err("bind: %m");
+ DEBUG("listen, ");
+ if (listen(sock, 1) < 0)
+ err("listen: %m");
+ DEBUG("accept, ");
+ for(;;) { /* infinite loop */
+ if ((net = accept(sock, (struct sockaddr *) &addrin, &addrinlen)) < 0)
+ err("accept: %m");
+
+ set_peername(net,clientname) ;
+ if (!authorized_client(clientname)) {
+ msg2(LOG_INFO,"Unauthorized client") ;
+ close(net) ;
+ continue ;
+ }
+ msg2(LOG_INFO,"Authorized client") ;
+ if ((newpid=fork())<0) {
+ msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ;
+ close(net) ;
+ continue ;
+ }
+ if (newpid>0) { /* parent */
+ close(net) ; continue ; }
+ /* child */
+ close(sock) ;
+ msg2(LOG_INFO,"Starting to serve") ;
+ serveconnection(net) ;
+ }
+}
+
+#define SEND writeit( net, &reply, sizeof( reply ));
+#define ERROR { reply.error = htonl(-1); SEND; reply.error = 0; lastpoint = -1; }
+
+fsoffset_t lastpoint = -1;
+
+void maybeseek(int handle, fsoffset_t a)
+{
+ if (a > exportsize)
+ err("Can not happen\n");
+ if (lastpoint != a) {
+#if defined(HAVE_LLSEEK) && !defined(FS_32BIT)
+ if (llseek(handle, a, SEEK_SET) < 0)
+#else
+ if (lseek(handle, (long)a, SEEK_SET) < 0)
+#endif
+ err("Can not seek locally!\n");
+ lastpoint = a;
+ } else {
+ DEBUG("@");
+ }
+}
+
+void myseek(int handle,fsoffset_t a)
+{
+#if HAVE_LLSEEK && !defined(FS_32BIT)
+ if (llseek(handle, a, SEEK_SET) < 0)
+#else
+ if (lseek(handle, (long)a, SEEK_SET) < 0)
+#endif
+ err("Can not seek locally!\n");
+}
+
+char pagebuf[DIFFPAGESIZE] ;
+
+
+int rawexpread(fsoffset_t a, char *buf, int len)
+{
+ maybeseek(export[a/hunksize], a%hunksize);
+ return (read(export[a/hunksize], buf, len) != len);
+}
+
+int expread(fsoffset_t a, char *buf, int len)
+{ int rdlen ; fsoffset_t mapcnt,mapl,maph ;
+ fsoffset_t pagestart; int offset ;
+
+ if (flags & F_COPYONWRITE) {
+ DEBUG3("Asked to read %d bytes at %lu.\n",len,(unsigned long)a) ;
+
+ mapl=a/DIFFPAGESIZE ; maph=(a+len-1)/DIFFPAGESIZE ;
+
+ for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
+ pagestart=mapcnt*DIFFPAGESIZE ;
+ offset=a-pagestart ;
+ rdlen=(len<DIFFPAGESIZE-offset) ? len : DIFFPAGESIZE-offset ;
+ if (difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
+ DEBUG3("Page %d is at %ld\n",(int)mapcnt,(long int)difmap[mapcnt]) ;
+ myseek(difffile,difmap[mapcnt]*DIFFPAGESIZE+offset) ;
+ if (read(difffile, buf, rdlen) != rdlen) return -1 ;
+ } else { /* the block is not there */
+ DEBUG2("Page %d is not here, we read the original one\n",
+ (int)mapcnt) ;
+ if (rawexpread(a,buf,rdlen)) return -1 ;
+ }
+ len-=rdlen ; a+=rdlen ; buf+=rdlen ;
+ }
+ } else return rawexpread(a,buf,len) ;
+ return 0 ;
+}
+
+int rawexpwrite(fsoffset_t a, char *buf, int len)
+{
+ maybeseek(export[a/hunksize], a%hunksize);
+ return (write(export[a/hunksize], buf, len) != len);
+}
+
+
+int expwrite(fsoffset_t a, char *buf, int len)
+{ u32 mapcnt,mapl,maph ; int wrlen,rdlen ;
+ fsoffset_t pagestart ; int offset ;
+
+ if (flags & F_COPYONWRITE) {
+ DEBUG3("Asked to write %d bytes at %lu.\n",len,(unsigned long)a) ;
+
+ mapl=a/DIFFPAGESIZE ; maph=(a+len-1)/DIFFPAGESIZE ;
+
+ for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
+ pagestart=mapcnt*DIFFPAGESIZE ;
+ offset=a-pagestart ;
+ wrlen=(len<DIFFPAGESIZE-offset) ? len : DIFFPAGESIZE-offset ;
+
+ if (difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
+ DEBUG3("Page %d is at %ld\n",mapcnt,(long)difmap[mapcnt]) ;
+ myseek(difffile,difmap[mapcnt]*DIFFPAGESIZE+offset) ;
+ if (write(difffile, buf, wrlen) != wrlen) return -1 ;
+ } else { /* the block is not there */
+ myseek(difffile,difffilelen*DIFFPAGESIZE) ;
+ difmap[mapcnt]=difffilelen++ ;
+ DEBUG3("Page %d is not here, we put it at %ld\n",
+ mapcnt,(long)difmap[mapcnt]) ;
+
+ rdlen=DIFFPAGESIZE ;
+ if (rdlen+pagestart%hunksize>hunksize)
+ rdlen=hunksize-(pagestart%hunksize) ;
+ if (rawexpread(pagestart,pagebuf,rdlen)) return -1 ;
+ memcpy(pagebuf+offset,buf,wrlen) ;
+ if (write(difffile,pagebuf,DIFFPAGESIZE)!=DIFFPAGESIZE) return -1 ;
+ }
+ len-=wrlen ; a+=wrlen ; buf+=wrlen ;
+ }
+ } else return(rawexpwrite(a,buf,len));
+ return 0 ;
+}
+
+int mainloop(int net)
+{
+ struct nbd_request request;
+ struct nbd_reply reply;
+ char zeros[300];
+ int i = 0;
+ fsoffset_t size_host;
+
+ memset(zeros, 0, 290);
+ if (write(net, INIT_PASSWD, 8) < 0)
+ err("Negotiation failed: %m");
+#ifndef FS_32BIT
+ cliserv_magic = htonll(cliserv_magic);
+#endif
+ if (write(net, &cliserv_magic, sizeof(cliserv_magic)) < 0)
+ err("Negotiation failed: %m");
+ size_host = htonll(exportsize);
+#ifdef FS_32BIT
+ if (write(net, zeros, 4) < 0 || write(net, &size_host, 4) < 0)
+#else
+ if (write(net, &size_host, 8) < 0)
+#endif
+ err("Negotiation failed: %m");
+ if (write(net, zeros, 128) < 0)
+ err("Negotiation failed: %m");
+
+ DEBUG("Entering request loop!\n");
+ reply.magic = htonl(NBD_REPLY_MAGIC);
+ reply.error = 0;
+ while (1) {
+ char buf[20480];
+ int len;
+
+#ifdef DODBG
+ i++;
+ printf("%d: ", i);
+#endif
+
+ readit(net, &request, sizeof(request));
+ request.from = ntohll(request.from);
+ request.type = ntohl(request.type);
+
+ if (request.type==2) { /* Disconnect request */
+ if (difmap) free(difmap) ;
+ if (difffile>=0) {
+ close(difffile) ; unlink(difffilename) ; }
+ err("Disconnect request received.") ;
+ }
+
+ len = ntohl(request.len);
+
+ if (request.magic != htonl(NBD_REQUEST_MAGIC))
+ err("Not enough magic.");
+ if (len > 10240)
+ err("Request too big!");
+#ifdef DODBG
+ printf("%s from %d (%d) len %d, ", (request.type ? "WRITE" : "READ"),
+ (int) request.from, (int) request.from / 512, len);
+#endif
+ memcpy(reply.handle, request.handle, sizeof(reply.handle));
+ if (((request.from + len) > exportsize) ||
+ ((flags & F_READONLY) && request.type)) {
+ DEBUG("[RANGE!]");
+ ERROR;
+ continue;
+ }
+ if (request.type==1) { /* WRITE */
+ DEBUG("wr: net->buf, ");
+ readit(net, buf, len);
+ DEBUG("buf->exp, ");
+ if (expwrite(request.from, buf, len)) {
+ DEBUG("Write failed: %m" );
+ ERROR;
+ continue;
+ }
+ lastpoint += len;
+ SEND;
+ continue;
+ }
+ /* READ */
+
+ DEBUG("exp->buf, ");
+ if (expread(request.from, buf + sizeof(struct nbd_reply), len)) {
+ lastpoint = -1;
+ DEBUG("Read failed: %m");
+ ERROR;
+ continue;
+ }
+ lastpoint += len;
+
+ DEBUG("buf->net, ");
+ memcpy(buf, &reply, sizeof(struct nbd_reply));
+ writeit(net, buf, len + sizeof(struct nbd_reply));
+ DEBUG("OK!\n");
+ }
+}
+
+char exportname2[1024];
+
+void set_peername(int net,char *clientname)
+{
+ struct sockaddr_in addrin;
+ int addrinlen = sizeof( addrin );
+ char *peername ;
+
+ if (getpeername( net, (struct sockaddr *) &addrin, &addrinlen ) < 0)
+ err("getsockname failed: %m");
+ peername = inet_ntoa(addrin.sin_addr);
+ sprintf(exportname2, exportname, peername);
+
+ msg4(LOG_INFO, "connect from %s, assigned file is %s", peername, exportname2);
+ strncpy(clientname,peername,255) ;
+}
+
+fsoffset_t size_autodetect(int export)
+{
+ fsoffset_t es;
+ DEBUG("looking for export size with lseek SEEK_END\n");
+ if ((int)(es = lseek(export, 0, SEEK_END)) == -1 || es == 0) {
+ struct stat stat_buf = { 0, } ;
+ int error;
+ DEBUG("looking for export size with fstat\n");
+ if ((error = fstat(export, &stat_buf)) == -1 || stat_buf.st_size == 0 ) {
+ DEBUG("looking for export size with ioctl BLKGETSIZE\n");
+#ifdef BLKGETSIZE
+ if(ioctl(export, BLKGETSIZE, &es) || es == 0) {
+#else
+ if(1){
+#endif
+ err("Could not find size of exported block device: %m");
+ } else {
+ es *= 512; /* assume blocksize 512 */
+ }
+ } else {
+ es = stat_buf.st_size;
+ }
+ }
+ return es;
+}
+
+int main(int argc, char *argv[])
+{
+ int net;
+ fsoffset_t i;
+
+ if (sizeof( struct nbd_request )!=28) {
+ fprintf(stderr,"Bad size of structure. Alignment problems?\n");
+ exit(-1) ;
+ }
+ logging();
+ cmdline(argc, argv);
+
+ if (!port) return 1 ;
+ connectme(port); /* serve infinitely */
+ return 0 ;
+}
+
+
+void serveconnection(int net)
+{
+ u64 i ;
+
+ for (i=0; i<exportsize; i+=hunksize) {
+ char exportname3[1024];
+
+ sprintf(exportname3, exportname2, i/hunksize);
+ printf( "Opening %s\n", exportname3 );
+ if ((export[i/hunksize] = open(exportname3, (flags & F_READONLY) ? O_RDONLY : O_RDWR)) == -1)
+ err("Could not open exported file: %m");
+ }
+
+ if (exportsize == (u64)~0) {
+ exportsize = size_autodetect(export[0]);
+ }
+ if (exportsize > (~0UL >> 1))
+#ifdef HAVE_LLSEEK
+ if ((exportsize >> 10) > (~0UL >> 1))
+ msg3(LOG_INFO, "size of exported file/device is %luMB",
+ (unsigned long)(exportsize >> 20));
+ else
+ msg3(LOG_INFO, "size of exported file/device is %luKB",
+ (unsigned long)(exportsize >> 10));
+#else
+ err("Size of exported file is too big\n");
+#endif
+ else
+ msg3(LOG_INFO, "size of exported file/device is %lu",
+ (unsigned long)exportsize);
+
+ if (flags & F_COPYONWRITE) {
+ sprintf(difffilename,"%s-%s-%d.diff",exportname2,clientname,
+ (int)getpid()) ;
+ msg3(LOG_INFO,"About to create map and diff file %s",difffilename) ;
+ difffile=open(difffilename,O_RDWR | O_CREAT | O_TRUNC,0600) ;
+ if (difffile<0) err("Could not create diff file (%m)") ;
+ if ((difmap=calloc(exportsize/DIFFPAGESIZE,sizeof(u32)))==NULL)
+ err("Could not allocate memory") ;
+ for (i=0;i<exportsize/DIFFPAGESIZE;i++) difmap[i]=(u32)-1 ;
+ }
+
+ setmysockopt(net);
+
+ mainloop(net);
+}