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