be5f3fd3cf7dce31afd2a9caae3e6705495abb5c
[nbd.git] / nbd-server.c
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 2002 Anton Altaparmakov <aia21@cam.ac.uk>
7  *
8  * Version 1.0 - hopefully 64-bit-clean
9  * Version 1.1 - merging enhancements from Josh Parsons, <josh@coombs.anu.edu.au>
10  * Version 1.2 - autodetect size of block devices, thanx to Peter T. Breuer" <ptb@it.uc3m.es>
11  * Version 1.5 - can compile on Unix systems that don't have 64 bit integer
12  *      type, or don't have 64 bit file offsets by defining FS_32BIT
13  *      in compile options for nbd-server *only*. This can be done
14  *      with make FSCHOICE=-DFS_32BIT nbd-server. (I don't have the
15  *      original autoconf input file, or I would make it a configure
16  *      option.) Ken Yap <ken@nlc.net.au>.
17  * Version 1.6 - fix autodetection of block device size and really make 64 bit
18  *      clean on 32 bit machines. Anton Altaparmakov <aia21@cam.ac.uk>
19  * Version 2.0 - Version synchronised with client
20  * Version 2.1 - Reap zombie client processes when they exit. Removed
21  *      (uncommented) the _IO magic, it's no longer necessary. Wouter
22  *      Verhelst <wouter@debian.org>
23  * Version 2.2 - Auto switch to read-only mode (usefull for floppies).
24  * Version 2.3 - Fixed code so that Large File Support works. This
25  *      removes the FS_32BIT compile-time directive; define
26  *      _FILE_OFFSET_BITS=64 and _LARGEFILE_SOURCE if you used to be
27  *      using FS_32BIT. This will allow you to use files >2GB instead of
28  *      having to use the -m option. Wouter Verhelst <wouter@debian.org>
29  * Version 2.4 - Added code to keep track of children, so that we can
30  *      properly kill them from initscripts. Add a call to daemon(),
31  *      so that processes don't think they have to wait for us, which is
32  *      interesting for initscripts as well. Wouter Verhelst
33  *      <wouter@debian.org>
34  * Version 2.5 - Bugfix release: forgot to reset child_arraysize to
35  *      zero after fork()ing, resulting in nbd-server going berserk
36  *      when it receives a signal with at least one child open. Wouter
37  *      Verhelst <wouter@debian.org>
38  * 10/10/2003 - Added socket option SO_KEEPALIVE (sf.net bug 819235);
39  *      rectified type of mainloop::size_host (sf.net bugs 814435 and
40  *      817385); close the PID file after writing to it, so that the
41  *      daemon can actually be found. Wouter Verhelst
42  *      <wouter@debian.org>
43  * 10/10/2003 - Size of the data "size_host" was wrong and so was not
44  *      correctly put in network endianness. Many types were corrected
45  *      (size_t and off_t instead of int).  <vspaceg@sourceforge.net>
46  */
47
48 #define VERSION PACKAGE_VERSION
49 #define GIGA (1*1024*1024*1024)
50
51 #include <sys/types.h>
52 #include <sys/socket.h>
53 #include <sys/stat.h>
54 #include <sys/wait.h>           /* wait */
55 #include <sys/ioctl.h>
56 #include <sys/param.h>
57 #include <sys/mount.h>          /* For BLKGETSIZE */
58 #include <signal.h>             /* sigaction */
59 #include <netinet/tcp.h>
60 #include <netinet/in.h>         /* sockaddr_in, htons, in_addr */
61 #include <netdb.h>              /* hostent, gethostby*, getservby* */
62 #include <syslog.h>
63 #include <unistd.h>
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <fcntl.h>
68 #include <arpa/inet.h>
69 #include <strings.h>
70
71 /* used in cliserv.h, so must be first */
72 #define MY_NAME "nbd_server"
73 #include "cliserv.h"
74
75 /* how much space for child PIDs we have by default. Dynamically
76    allocated, and will be realloc()ed if out of space, so this should
77    probably be fair for most situations. */
78 #define DEFAULT_CHILD_ARRAY 256
79
80 /* Debugging macros, now nothing goes to syslog unless you say ISSERVER */
81 #ifdef ISSERVER
82 #define msg2(a,b) syslog(a,b)
83 #define msg3(a,b,c) syslog(a,b,c)
84 #define msg4(a,b,c,d) syslog(a,b,c,d)
85 #else
86 #define msg2(a,b) do { fprintf(stderr,b) ; fputs("\n",stderr) ; } while(0) 
87 #define msg3(a,b,c) do { fprintf(stderr,b,c); fputs("\n",stderr) ; } while(0) 
88 #define msg4(a,b,c,d) do { fprintf(stderr,b,c,d); fputs("\n",stderr) ; } while(0)
89 #endif
90
91 //#define DODBG
92 #ifdef DODBG
93 #define DEBUG( a ) printf( a )
94 #define DEBUG2( a,b ) printf( a,b )
95 #define DEBUG3( a,b,c ) printf( a,b,c )
96 #else
97 #define DEBUG( a )
98 #define DEBUG2( a,b ) 
99 #define DEBUG3( a,b,c ) 
100 #endif
101
102 #ifndef PACKAGE_VERSION
103 #define PACKAGE_VERSION ""
104 #endif
105
106 /* This is starting to get ugly. If someone knows a better way to find
107  * the maximum value of a signed type *without* relying on overflow
108  * (doing so breaks on 64bit architectures), that would be nice.
109  */
110 #define OFFT_MAX (((((off_t)1)<<((sizeof(off_t)-1)*8))-1)<<7)+127
111
112 void serveconnection(int net);
113 void set_peername(int net,char *clientname);
114
115 #define LINELEN 256 
116 char difffilename[256];
117 unsigned int timeout = 0;
118 int autoreadonly = 0;
119 char *auth_file="nbd_server.allow";
120
121 int authorized_client(char *name)
122 /* 0 - authorization refused, 1 - OK 
123   authorization file contains one line per machine, no wildcards
124 */
125 {
126         FILE *f ;
127    
128         char line[LINELEN] ; 
129
130         if ((f=fopen(auth_file,"r"))==NULL) {
131                 msg4(LOG_INFO,"Can't open authorization file %s (%s).",
132                      auth_file,strerror(errno)) ;
133                 return 1 ; 
134         }
135   
136         while (fgets(line,LINELEN,f)!=NULL) {
137                 if (strncmp(line,name,strlen(name))==0) {
138                         fclose(f);
139                         return 1;
140                 }
141         }
142         fclose(f) ;
143         return 0 ;
144 }
145
146 inline void readit(int f, void *buf, size_t len)
147 {
148         ssize_t res;
149         while (len > 0) {
150                 DEBUG("*");
151                 if ((res = read(f, buf, len)) <= 0)
152                         err("Read failed: %m");
153                 len -= res;
154                 buf += res;
155         }
156 }
157
158 inline void writeit(int f, void *buf, size_t len)
159 {
160         ssize_t res;
161         while (len > 0) {
162                 DEBUG("+");
163                 if ((res = send(f, buf, len, 0)) <= 0)
164                         err("Send failed: %m");
165                 len -= res;
166                 buf += res;
167         }
168 }
169
170 unsigned int port;                      /* Port I'm listening at */
171 char *exportname;               /* File I'm exporting */
172 off_t exportsize = OFFT_MAX;    /* ...and its length */
173 off_t hunksize = OFFT_MAX;
174 int flags = 0;
175 int export[1024];
176 int difffile=-1 ;
177 u32 difffilelen=0 ; /* number of pages in difffile */
178 u32 *difmap=NULL ;
179 char clientname[256] ;
180 int child_arraysize=DEFAULT_CHILD_ARRAY;
181 pid_t *children;
182 char pidfname[256];
183
184 #define DIFFPAGESIZE 4096 /* diff file uses those chunks */
185
186 #define F_READONLY 1
187 #define F_MULTIFILE 2 
188 #define F_COPYONWRITE 4
189
190 void cmdline(int argc, char *argv[])
191 {
192         int i;
193
194         if (argc < 3) {
195                 printf("This is nbd-server version " VERSION "\n");     
196                 printf("Usage: port file_to_export [size][kKmM] [-r] [-m] [-c] [-a timeout_sec]\n"
197                        "        -r read only\n"
198                        "        -m multiple file\n"
199                        "        -c copy on write\n"
200                        "        -l file with list of hosts that are allowed to connect.\n"
201                        "        -a maximum idle seconds, terminates when idle time exceeded\n"
202                        "        if port is set to 0, stdin is used (for running from inetd)\n"
203                        "        if file_to_export contains '%%s', it is substituted with IP\n"
204                        "                address of machine trying to connect\n" );
205                 exit(0);
206         }
207         port = atoi(argv[1]);
208         for (i = 3; i < argc; i++) {
209                 if (*argv[i] == '-') {
210                         switch (argv[i][1]) {
211                         case 'r':
212                                 flags |= F_READONLY;
213                                 break;
214                         case 'm':
215                                 flags |= F_MULTIFILE;
216                                 hunksize = 1*GIGA;
217                                 break;
218                         case 'c': flags |=F_COPYONWRITE;
219                                 break;
220                         case 'l':
221                                 free(auth_file);
222                                 if (i+1<argc) {
223                                         auth_file=argv[++i];
224                                 } else {
225                                         fprintf(stderr, "host list file requires an argument");
226                                 }
227                                 break;
228                         case 'a': 
229                                 if (i+1<argc) {
230                                         timeout = atoi(argv[i+1]);
231                                         i++;
232                                 } else {
233                                         fprintf(stderr, "timeout requires argument\n");
234                                         exit(1);
235                                 }
236                         }
237                 } else {
238                         off_t es;
239                         size_t last = strlen(argv[i])-1;
240                         char suffix = argv[i][last];
241                         if (suffix == 'k' || suffix == 'K' ||
242                             suffix == 'm' || suffix == 'M')
243                                 argv[i][last] = '\0';
244                         es = (off_t)atol(argv[i]);
245                         switch (suffix) {
246                                 case 'm':
247                                 case 'M':  es <<= 10;
248                                 case 'k':
249                                 case 'K':  es <<= 10;
250                                 default :  break;
251                         }
252                         exportsize = es;
253                 }
254         }
255
256         exportname = argv[2];
257 }
258
259 void sigchld_handler(int s)
260 {
261         int* status=NULL;
262         int i;
263         pid_t pid;
264
265         while((pid=wait(status)) > 0) {
266                 if(WIFEXITED(status)) {
267                         msg3(LOG_INFO, "Child exited with %d", WEXITSTATUS(status));
268                 }
269                 for(i=0;children[i]!=pid&&i<child_arraysize;i++);
270                 if(i>=child_arraysize) {
271                         msg3(LOG_INFO, "SIGCHLD received for an unknown child with PID %ld",(long) pid);
272                 } else {
273                         children[i]=(pid_t)0;
274                         DEBUG2("Removing %d from the list of children", pid);
275                 }
276         }
277 }
278
279 /* If we are terminated, make sure our children are, too. */
280 void sigterm_handler(int s) {
281         int i;
282         int parent=0;
283
284         for(i=0;i<child_arraysize;i++) {
285                 if(children[i]) {
286                         kill(children[i], s);
287                         parent=1;
288                 }
289         }
290
291         if(parent) {
292                 unlink(pidfname);
293         }
294                 
295         exit(0);
296 }
297
298 void connectme(unsigned int port)
299 {
300         struct sockaddr_in addrin;
301         struct sigaction sa;
302         int addrinlen = sizeof(addrin);
303         int net, sock, newpid, i;
304 #ifndef sun
305         int yes=1;
306 #else
307         char yes='1';
308 #endif /* sun */
309 #ifndef NODAEMON
310 #ifndef NOFORK
311         FILE*pidf;
312
313         if(port) {
314                 if(daemon(0,0)<0) {
315                         err("daemon");
316                 }
317                 snprintf(pidfname, sizeof(char)*255, "/var/run/nbd-server.%d.pid", port);
318                 pidf=fopen(pidfname, "w");
319                 if(pidf) {
320                         fprintf(pidf,"%d", (int)getpid());
321                         fclose(pidf);
322                 } else {
323                         perror("fopen");
324                         fprintf(stderr, "Not fatal; continuing");
325                 }
326         }
327 #endif /* NOFORK */
328 #endif /* NODAEMON */
329
330         if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
331                 err("socket: %m");
332
333         /* lose the pesky "Address already in use" error message */
334         if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
335                 err("setsockopt SO_REUSEADDR");
336         }
337         if (setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,&yes,sizeof(int)) == -1) {
338                 err("setsockopt SO_KEEPALIVE");
339         }
340
341         DEBUG("Waiting for connections... bind, ");
342         addrin.sin_family = AF_INET;
343         addrin.sin_port = htons(port);
344         addrin.sin_addr.s_addr = 0;
345         if (bind(sock, (struct sockaddr *) &addrin, addrinlen) < 0)
346                 err("bind: %m");
347         DEBUG("listen, ");
348         if (listen(sock, 1) < 0)
349                 err("listen: %m");
350         DEBUG("accept, ");
351         sa.sa_handler = sigchld_handler;
352         sigemptyset(&sa.sa_mask);
353         sa.sa_flags = SA_RESTART;
354         if(sigaction(SIGCHLD, &sa, NULL) == -1)
355                 err("sigaction: %m");
356         sa.sa_handler = sigterm_handler;
357         sigemptyset(&sa.sa_mask);
358         sa.sa_flags = SA_RESTART;
359         if(sigaction(SIGTERM, &sa, NULL) == -1)
360                 err("sigaction: %m");
361         children=malloc(sizeof(pid_t)*child_arraysize);
362         memset(children, 0, sizeof(pid_t)*DEFAULT_CHILD_ARRAY);
363         for(;;) { /* infinite loop */
364                 if ((net = accept(sock, (struct sockaddr *) &addrin, &addrinlen)) < 0)
365                         err("accept: %m");
366                 
367                 set_peername(net,clientname) ;
368                 if (!authorized_client(clientname)) {
369                         msg2(LOG_INFO,"Unauthorized client") ;
370                         close(net) ;
371                         continue ;
372                 }
373                 msg2(LOG_INFO,"Authorized client") ;
374                 for(i=0;children[i]&&i<child_arraysize;i++);
375                 if(i>=child_arraysize) {
376                         pid_t*ptr;
377
378                         ptr=realloc(children, sizeof(pid_t)*child_arraysize);
379                         if(ptr) {
380                                 children=ptr;
381                                 memset(children+child_arraysize, 0, sizeof(pid_t)*DEFAULT_CHILD_ARRAY);
382                                 i=child_arraysize+1;
383                                 child_arraysize+=DEFAULT_CHILD_ARRAY;
384                         } else {
385                                 msg2(LOG_INFO,"Not enough memory to store child PID");
386                                 close(net);
387                                 continue;
388                         }
389                 }
390 #ifndef NOFORK
391                 if ((children[i]=fork())<0) {
392                         msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ;
393                         close(net) ;
394                         continue ;
395                 }
396                 if (children[i]>0) { /* parent */
397                         close(net) ; continue ; }
398                 /* child */
399                 realloc(children,0);
400                 child_arraysize=0;
401                 close(sock) ;
402 #endif // NOFORK
403                 msg2(LOG_INFO,"Starting to serve") ;
404                 serveconnection(net) ;        
405         }
406 }
407
408 #define SEND writeit( net, &reply, sizeof( reply ));
409 #define ERROR { reply.error = htonl(-1); SEND; reply.error = 0; lastpoint = -1; }
410
411 off_t lastpoint = (off_t)-1;
412
413 void maybeseek(int handle, off_t a)
414 {
415 if (a < 0 || a > exportsize)
416         err("Can not happen\n");
417 if (lastpoint != a) {
418         if (lseek(handle, a, SEEK_SET) < 0)
419                 err("Can not seek locally!\n");
420         lastpoint = a;
421 } else {
422         DEBUG("@");
423 }
424 }
425
426 void myseek(int handle,off_t a)
427 {
428         if (lseek(handle, a, SEEK_SET) < 0)
429                 err("Can not seek locally!\n");
430 }
431
432 char pagebuf[DIFFPAGESIZE];
433
434 int rawexpread(off_t a, char *buf, size_t len)
435 {
436         ssize_t res;
437
438         maybeseek(export[a/hunksize], a%hunksize);
439         res = read(export[a/hunksize], buf, len);
440         return (res < 0 || (size_t)res != len);
441 }
442
443 int expread(off_t a, char *buf, size_t len)
444 {
445         off_t rdlen, offset;
446         off_t mapcnt, mapl, maph, pagestart;
447  
448         if (!(flags & F_COPYONWRITE))
449                 return rawexpread(a, buf, len);
450         DEBUG3("Asked to read %d bytes at %Lu.\n", len, (unsigned long long)a);
451
452         mapl=a/DIFFPAGESIZE; maph=(a+len-1)/DIFFPAGESIZE;
453
454         for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
455                 pagestart=mapcnt*DIFFPAGESIZE;
456                 offset=a-pagestart;
457                 rdlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
458                         len : (size_t)DIFFPAGESIZE-offset;
459                 if (difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
460                         DEBUG3("Page %Lu is at %lu\n", (unsigned long long)mapcnt,
461                                (unsigned long)difmap[mapcnt]);
462                         myseek(difffile, difmap[mapcnt]*DIFFPAGESIZE+offset);
463                         if (read(difffile, buf, rdlen) != rdlen) return -1;
464                 } else { /* the block is not there */
465                         DEBUG2("Page %Lu is not here, we read the original one\n",
466                                (unsigned long long)mapcnt);
467                         return rawexpread(a, buf, rdlen);
468                 }
469                 len-=rdlen; a+=rdlen; buf+=rdlen;
470         }
471         return 0;
472 }
473
474 int rawexpwrite(off_t a, char *buf, size_t len)
475 {
476         ssize_t res;
477
478         maybeseek(export[a/hunksize], a%hunksize);
479         res = write(export[a/hunksize], buf, len);
480         return (res < 0 || (size_t)res != len);
481 }
482
483
484 int expwrite(off_t a, char *buf, size_t len)
485 {
486         off_t mapcnt,mapl,maph ;
487         off_t wrlen,rdlen ; 
488         off_t pagestart ;
489         off_t offset ;
490
491         if (!(flags & F_COPYONWRITE))
492                 return(rawexpwrite(a,buf,len)); 
493         DEBUG3("Asked to write %d bytes at %Lu.\n", len, (unsigned long long)a);
494
495         mapl=a/DIFFPAGESIZE ; maph=(a+len-1)/DIFFPAGESIZE ;
496
497         for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
498                 pagestart=mapcnt*DIFFPAGESIZE ;
499                 offset=a-pagestart ;
500                 wrlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
501                         len : (size_t)DIFFPAGESIZE-offset;
502
503                 if (difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
504                         DEBUG3("Page %Lu is at %lu\n", (unsigned long long)mapcnt,
505                                (unsigned long)difmap[mapcnt]) ;
506                         myseek(difffile,difmap[mapcnt]*DIFFPAGESIZE+offset) ;
507                         if (write(difffile, buf, wrlen) != wrlen) return -1 ;
508                 } else { /* the block is not there */
509                         myseek(difffile,difffilelen*DIFFPAGESIZE) ;
510                         difmap[mapcnt]=difffilelen++ ;
511                         DEBUG3("Page %Lu is not here, we put it at %lu\n",
512                                (unsigned long long)mapcnt,
513                                (unsigned long)difmap[mapcnt]);
514                         rdlen=DIFFPAGESIZE ;
515                         if (rdlen+pagestart%hunksize>hunksize) 
516                                 rdlen=hunksize-(pagestart%hunksize) ;
517                         if (rawexpread(pagestart,pagebuf,rdlen)) return -1 ;
518                         memcpy(pagebuf+offset,buf,wrlen) ;
519                         if (write(difffile,pagebuf,DIFFPAGESIZE)!=DIFFPAGESIZE) return -1 ;
520                 }                                                   
521                 len-=wrlen ; a+=wrlen ; buf+=wrlen ;
522         }
523         return 0;
524 }
525
526 int mainloop(int net)
527 {
528         struct nbd_request request;
529         struct nbd_reply reply;
530         char zeros[300];
531         int i = 0;
532         u64 size_host;
533
534         memset(zeros, 0, 290);
535         if (write(net, INIT_PASSWD, 8) < 0)
536                 err("Negotiation failed: %m");
537         cliserv_magic = htonll(cliserv_magic);
538         if (write(net, &cliserv_magic, sizeof(cliserv_magic)) < 0)
539                 err("Negotiation failed: %m");
540         size_host = htonll((u64)exportsize);
541         if (write(net, &size_host, 8) < 0)
542                 err("Negotiation failed: %m");
543         if (write(net, zeros, 128) < 0)
544                 err("Negotiation failed: %m");
545
546         DEBUG("Entering request loop!\n");
547         reply.magic = htonl(NBD_REPLY_MAGIC);
548         reply.error = 0;
549         while (1) {
550 #define BUFSIZE (1024*1024)
551                 char buf[BUFSIZE];
552                 size_t len;
553 #ifdef DODBG
554                 i++;
555                 printf("%d: ", i);
556 #endif
557
558                 if (timeout) 
559                         alarm(timeout);
560                 readit(net, &request, sizeof(request));
561                 request.from = ntohll(request.from);
562                 request.type = ntohl(request.type);
563
564                 if (request.type==2) { /* Disconnect request */
565                   if (difmap) free(difmap) ;
566                   if (difffile>=0) { 
567                      close(difffile) ; unlink(difffilename) ; }
568                   err("Disconnect request received.") ;
569                 }
570
571                 len = ntohl(request.len);
572
573                 if (request.magic != htonl(NBD_REQUEST_MAGIC))
574                         err("Not enough magic.");
575                 if (len > BUFSIZE)
576                         err("Request too big!");
577 #ifdef DODBG
578                 printf("%s from %Lu (%Lu) len %d, ", request.type ? "WRITE" :
579                                 "READ", (unsigned long long)request.from,
580                                 (unsigned long long)request.from / 512, len);
581 #endif
582                 memcpy(reply.handle, request.handle, sizeof(reply.handle));
583                 if ((request.from + len) > (OFFT_MAX)) {
584                   DEBUG("[Number too large!]");
585                   ERROR;
586                   continue;
587                 }
588                 if (((size_t)((off_t)request.from + len) > exportsize) ||
589                     ((flags & F_READONLY) && request.type)) {
590                         DEBUG("[RANGE!]");
591                         ERROR;
592                         continue;
593                 }
594                 if (request.type==1) {  /* WRITE */
595                         DEBUG("wr: net->buf, ");
596                         readit(net, buf, len);
597                         DEBUG("buf->exp, ");
598                         if ((autoreadonly == 1) || expwrite(request.from, buf, len)) {
599                                 DEBUG("Write failed: %m" );
600                                 ERROR;
601                                 continue;
602                         }
603                         lastpoint += len;
604                         SEND;
605                         DEBUG("OK!\n");
606                         continue;
607                 }
608                 /* READ */
609
610                 DEBUG("exp->buf, ");
611                 if (expread(request.from, buf + sizeof(struct nbd_reply), len)) {
612                         lastpoint = -1;
613                         DEBUG("Read failed: %m");
614                         ERROR;
615                         continue;
616                 }
617                 lastpoint += len;
618
619                 DEBUG("buf->net, ");
620                 memcpy(buf, &reply, sizeof(struct nbd_reply));
621                 writeit(net, buf, len + sizeof(struct nbd_reply));
622                 DEBUG("OK!\n");
623         }
624 }
625
626 char exportname2[1024];
627
628 void set_peername(int net,char *clientname)
629 {
630         struct sockaddr_in addrin;
631         int addrinlen = sizeof( addrin );
632         char *peername ;
633
634         if (getpeername( net, (struct sockaddr *) &addrin, &addrinlen ) < 0)
635                 err("getsockname failed: %m");
636         peername = inet_ntoa(addrin.sin_addr);
637         sprintf(exportname2, exportname, peername);
638
639         msg4(LOG_INFO, "connect from %s, assigned file is %s", peername, exportname2);
640         strncpy(clientname,peername,255) ;
641 }
642
643 off_t size_autodetect(int export)
644 {
645         off_t es;
646         u32 es32;
647         struct stat stat_buf;
648         int error;
649         
650         DEBUG("looking for export size with lseek SEEK_END\n");
651         es = lseek(export, (off_t)0, SEEK_END);
652         if (es > ((off_t)0)) {
653                 return es;
654         } else {
655                 DEBUG2("lseek failed: %d", errno==EBADF?1:(errno==ESPIPE?2:(errno==EINVAL?3:4)));
656         }
657         
658         DEBUG("looking for export size with fstat\n");
659         stat_buf.st_size = 0;
660         error = fstat(export, &stat_buf);
661         if (!error && stat_buf.st_size > 0) {
662                 return (off_t)stat_buf.st_size;
663         } else {
664                 err("fstat failed: %m");
665         }
666         
667 #ifdef BLKGETSIZE
668         DEBUG("looking for export size with ioctl BLKGETSIZE\n");
669         if (!ioctl(export, BLKGETSIZE, &es32) && es32) {
670                 es = (off_t)es32 * (off_t)512;
671                 return es;
672         }
673 #endif
674         err("Could not find size of exported block device: %m");
675         return OFFT_MAX;
676 }
677
678 int main(int argc, char *argv[])
679 {
680         if (sizeof( struct nbd_request )!=28) {
681                 fprintf(stderr,"Bad size of structure. Alignment problems?\n");
682                 exit(-1) ;
683         }
684         logging();
685         cmdline(argc, argv);
686         
687         if (!port) return 1 ;
688         connectme(port); /* serve infinitely */
689         return 0 ;
690 }
691
692
693 void serveconnection(int net) 
694 {   
695         off_t i ;
696         
697         for (i=0; i<exportsize; i+=hunksize) {
698                 char exportname3[1024];
699                 
700                 sprintf(exportname3, exportname2, i/hunksize);
701                 printf( "Opening %s\n", exportname3 );
702                 if ((export[i/hunksize] = open(exportname3, (flags & F_READONLY) ? O_RDONLY : O_RDWR)) == -1) {
703                         /* Read WRITE ACCESS was requested by media is only read only */
704                         autoreadonly = 1;
705                         flags |= F_READONLY;
706                         if ((export[i/hunksize] = open(exportname3, O_RDONLY)) == -1) 
707                                 err("Could not open exported file: %m");
708                 }
709         }
710         
711         if (exportsize == OFFT_MAX) {
712                 exportsize = size_autodetect(export[0]);
713         }
714         if (exportsize > OFFT_MAX) {
715                 err("Size of exported file is too big\n");
716         }
717         else
718                 msg3(LOG_INFO, "size of exported file/device is %Lu",
719                      (unsigned long long)exportsize);
720         
721         if (flags & F_COPYONWRITE) {
722                 sprintf(difffilename,"%s-%s-%d.diff",exportname2,clientname,
723                         (int)getpid()) ;
724                 msg3(LOG_INFO,"About to create map and diff file %s",difffilename) ;
725                 difffile=open(difffilename,O_RDWR | O_CREAT | O_TRUNC,0600) ;
726                 if (difffile<0) err("Could not create diff file (%m)") ;
727                 if ((difmap=calloc(exportsize/DIFFPAGESIZE,sizeof(u32)))==NULL)
728                         err("Could not allocate memory") ;
729                 for (i=0;i<exportsize/DIFFPAGESIZE;i++) difmap[i]=(u32)-1 ;       
730         }
731         
732         setmysockopt(net);
733         
734         mainloop(net);
735 }