bd4650752c66f4a4c75320d7a26ecc619d81bc1a
[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 /* Authorization file should contain lines with IP addresses of 
61    clients authorized to use the server. If it does not exist,
62    access is permitted. 
63    
64    You may want to set this to an absolute path if you're not using
65    -DNODAEMON, since if you don't, nbd-server will look for this file
66    in the root-directory ("/"). */
67 #define AUTH_FILE "nbd_server.allow"
68 /* how much space for child PIDs we have by default. Dynamically
69    allocated, and will be realloc()ed if out of space, so this should
70    probably be fair for most situations. */
71 #define DEFAULT_CHILD_ARRAY 256
72
73 #include "cliserv.h"
74 //#undef _IO
75 /* Deep magic: ioctl.h defines _IO macro (at least on linux) */
76
77
78 /* Debugging macros, now nothing goes to syslog unless you say ISSERVER */
79 #ifdef ISSERVER
80 #define msg2(a,b) syslog(a,b)
81 #define msg3(a,b,c) syslog(a,b,c)
82 #define msg4(a,b,c,d) syslog(a,b,c,d)
83 #else
84 #define msg2(a,b) do { fprintf(stderr,b) ; fputs("\n",stderr) ; } while(0) 
85 #define msg3(a,b,c) do { fprintf(stderr,b,c); fputs("\n",stderr) ; } while(0) 
86 #define msg4(a,b,c,d) do { fprintf(stderr,b,c,d); fputs("\n",stderr) ; } while(0)
87 #endif
88
89
90 #include <sys/ioctl.h>
91 #include <sys/mount.h>          /* For BLKGETSIZE */
92
93 //#define DODBG
94 #ifdef DODBG
95 #define DEBUG( a ) printf( a )
96 #define DEBUG2( a,b ) printf( a,b )
97 #define DEBUG3( a,b,c ) printf( a,b,c )
98 #else
99 #define DEBUG( a )
100 #define DEBUG2( a,b ) 
101 #define DEBUG3( a,b,c ) 
102 #endif
103
104 void serveconnection(int net);
105 void set_peername(int net,char *clientname);
106
107 #define LINELEN 256 
108 char difffilename[256];
109 unsigned int timeout = 0;
110 int autoreadonly = 0;
111
112 int authorized_client(char *name)
113 /* 0 - authorization refused, 1 - OK 
114   authorization file contains one line per machine, no wildcards
115 */
116 {
117         FILE *f ;
118    
119         char line[LINELEN] ; 
120
121         if ((f=fopen(AUTH_FILE,"r"))==NULL) {
122                 msg4(LOG_INFO,"Can't open authorization file %s (%s).",
123                      AUTH_FILE,strerror(errno)) ;
124                 return 1 ; 
125         }
126   
127         while (fgets(line,LINELEN,f)!=NULL) {
128                 if (strncmp(line,name,strlen(name))==0) {
129                         fclose(f);
130                         return 1;
131                 }
132         }
133         fclose(f) ;
134         return 0 ;
135 }
136
137 inline void readit(int f, void *buf, int len)
138 {
139         int res;
140         while (len > 0) {
141                 DEBUG("*");
142                 if ((res = read(f, buf, len)) <= 0)
143                         err("Read failed: %m");
144                 len -= res;
145                 buf += res;
146         }
147 }
148
149 inline void writeit(int f, void *buf, int len)
150 {
151         int res;
152         while (len > 0) {
153                 DEBUG("+");
154                 if ((res = send(f, buf, len, 0)) <= 0)
155                         err("Send failed: %m");
156                 len -= res;
157                 buf += res;
158         }
159 }
160
161 /* This is starting to get ugly. If someone knows a better way to find
162  * the maximum value of a signed type *without* relying on overflow
163  * (doing so breaks on 64bit architectures), that would be nice.
164  */
165 #define OFFT_MAX (((((off_t)1)<<((sizeof(off_t)-1)*8))-1)<<7)+127
166 int port;                       /* Port I'm listening at */
167 char *exportname;               /* File I'm exporting */
168 off_t exportsize = OFFT_MAX;    /* ...and its length */
169 off_t hunksize = OFFT_MAX;
170 int flags = 0;
171 int export[1024];
172 int difffile=-1 ;
173 u32 difffilelen=0 ; /* number of pages in difffile */
174 u32 *difmap=NULL ;
175 char clientname[256] ;
176 int child_arraysize=DEFAULT_CHILD_ARRAY;
177 pid_t *children;
178 char pidfname[256];
179
180 #define DIFFPAGESIZE 4096 /* diff file uses those chunks */
181
182 #define F_READONLY 1
183 #define F_MULTIFILE 2 
184 #define F_COPYONWRITE 4
185
186 void cmdline(int argc, char *argv[])
187 {
188         int i;
189
190         if (argc < 3) {
191                 printf("This is nbd-server version " VERSION "\n");     
192                 printf("Usage: port file_to_export [size][kKmM] [-r] [-m] [-c] [-a timeout_sec]\n"
193                        "        -r read only\n"
194                        "        -m multiple file\n"
195                        "        -c copy on write\n"
196                        "        -a maximum idle seconds, terminates when idle time exceeded\n"
197                        "        if port is set to 0, stdin is used (for running from inetd)\n"
198                        "        if file_to_export contains '%%s', it is substituted with IP\n"
199                        "                address of machine trying to connect\n" );
200                 exit(0);
201         }
202         port = atoi(argv[1]);
203         for (i = 3; i < argc; i++) {
204                 if (*argv[i] == '-') {
205                         switch (argv[i][1]) {
206                         case 'r':
207                                 flags |= F_READONLY;
208                                 break;
209                         case 'm':
210                                 flags |= F_MULTIFILE;
211                                 hunksize = 1*GIGA;
212                                 break;
213                         case 'c': flags |=F_COPYONWRITE;
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                 close(sock) ;
375 #endif // NOFORK
376                 msg2(LOG_INFO,"Starting to serve") ;
377                 serveconnection(net) ;        
378         }
379 }
380
381 #define SEND writeit( net, &reply, sizeof( reply ));
382 #define ERROR { reply.error = htonl(-1); SEND; reply.error = 0; lastpoint = -1; }
383
384 off_t lastpoint = (off_t)-1;
385
386 void maybeseek(int handle, off_t a)
387 {
388 if (a > exportsize)
389         err("Can not happen\n");
390 if (lastpoint != a) {
391         if (lseek(handle, a, SEEK_SET) < 0)
392                 err("Can not seek locally!\n");
393         lastpoint = a;
394 } else {
395         DEBUG("@");
396 }
397 }
398
399 void myseek(int handle,off_t a)
400 {
401         if (lseek(handle, a, SEEK_SET) < 0)
402                 err("Can not seek locally!\n");
403 }
404
405 char pagebuf[DIFFPAGESIZE];
406
407 int rawexpread(off_t a, char *buf, int len)
408 {
409         maybeseek(export[a/hunksize], a%hunksize);
410         return (read(export[a/hunksize], buf, len) != len);
411 }
412
413 int expread(off_t a, char *buf, int len)
414 {
415         int rdlen, offset;
416         off_t mapcnt, mapl, maph, pagestart;
417  
418         if (!(flags & F_COPYONWRITE))
419                 return rawexpread(a, buf, len);
420         DEBUG3("Asked to read %d bytes at %Lu.\n", len, (unsigned long long)a);
421
422         mapl=a/DIFFPAGESIZE; maph=(a+len-1)/DIFFPAGESIZE;
423
424         for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
425                 pagestart=mapcnt*DIFFPAGESIZE;
426                 offset=a-pagestart;
427                 rdlen=(len<DIFFPAGESIZE-offset) ? len : DIFFPAGESIZE-offset;
428                 if (difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
429                         DEBUG3("Page %Lu is at %lu\n", (unsigned long long)mapcnt,
430                                (unsigned long)difmap[mapcnt]);
431                         myseek(difffile, difmap[mapcnt]*DIFFPAGESIZE+offset);
432                         if (read(difffile, buf, rdlen) != rdlen) return -1;
433                 } else { /* the block is not there */
434                         DEBUG2("Page %Lu is not here, we read the original one\n",
435                                (unsigned long long)mapcnt);
436                         return rawexpread(a, buf, rdlen);
437                 }
438                 len-=rdlen; a+=rdlen; buf+=rdlen;
439         }
440         return 0;
441 }
442
443 int rawexpwrite(off_t a, char *buf, int len)
444 {
445         maybeseek(export[a/hunksize], a%hunksize);
446         return (write(export[a/hunksize], buf, len) != len);
447 }
448
449
450 int expwrite(off_t a, char *buf, int len)
451 {
452         u32 mapcnt,mapl,maph ; int wrlen,rdlen ; 
453         off_t pagestart ; int offset ;
454
455         if (!(flags & F_COPYONWRITE))
456                 return(rawexpwrite(a,buf,len)); 
457         DEBUG3("Asked to write %d bytes at %Lu.\n", len, (unsigned long long)a);
458
459         mapl=a/DIFFPAGESIZE ; maph=(a+len-1)/DIFFPAGESIZE ;
460
461         for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
462                 pagestart=mapcnt*DIFFPAGESIZE ;
463                 offset=a-pagestart ;
464                 wrlen=(len<DIFFPAGESIZE-offset) ? len : DIFFPAGESIZE-offset ;
465
466                 if (difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
467                         DEBUG3("Page %Lu is at %lu\n", (unsigned long long)mapcnt,
468                                (unsigned long)difmap[mapcnt]) ;
469                         myseek(difffile,difmap[mapcnt]*DIFFPAGESIZE+offset) ;
470                         if (write(difffile, buf, wrlen) != wrlen) return -1 ;
471                 } else { /* the block is not there */
472                         myseek(difffile,difffilelen*DIFFPAGESIZE) ;
473                         difmap[mapcnt]=difffilelen++ ;
474                         DEBUG3("Page %Lu is not here, we put it at %lu\n",
475                                (unsigned long long)mapcnt,
476                                (unsigned long)difmap[mapcnt]);
477                         rdlen=DIFFPAGESIZE ;
478                         if (rdlen+pagestart%hunksize>hunksize) 
479                                 rdlen=hunksize-(pagestart%hunksize) ;
480                         if (rawexpread(pagestart,pagebuf,rdlen)) return -1 ;
481                         memcpy(pagebuf+offset,buf,wrlen) ;
482                         if (write(difffile,pagebuf,DIFFPAGESIZE)!=DIFFPAGESIZE) return -1 ;
483                 }                                                   
484                 len-=wrlen ; a+=wrlen ; buf+=wrlen ;
485         }
486         return 0;
487 }
488
489 int mainloop(int net)
490 {
491         struct nbd_request request;
492         struct nbd_reply reply;
493         char zeros[300];
494         int i = 0;
495         off_t size_host;
496
497         memset(zeros, 0, 290);
498         if (write(net, INIT_PASSWD, 8) < 0)
499                 err("Negotiation failed: %m");
500         cliserv_magic = htonll(cliserv_magic);
501         if (write(net, &cliserv_magic, sizeof(cliserv_magic)) < 0)
502                 err("Negotiation failed: %m");
503         size_host = htonll(exportsize);
504         if (write(net, &size_host, 8) < 0)
505                 err("Negotiation failed: %m");
506         if (write(net, zeros, 128) < 0)
507                 err("Negotiation failed: %m");
508
509         DEBUG("Entering request loop!\n");
510         reply.magic = htonl(NBD_REPLY_MAGIC);
511         reply.error = 0;
512         while (1) {
513 #define BUFSIZE (1024*1024)
514                 char buf[BUFSIZE];
515                 int len;
516 #ifdef DODBG
517                 i++;
518                 printf("%d: ", i);
519 #endif
520
521                 if (timeout) 
522                         alarm(timeout);
523                 readit(net, &request, sizeof(request));
524                 request.from = ntohll(request.from);
525                 request.type = ntohl(request.type);
526
527                 if (request.type==2) { /* Disconnect request */
528                   if (difmap) free(difmap) ;
529                   if (difffile>=0) { 
530                      close(difffile) ; unlink(difffilename) ; }
531                   err("Disconnect request received.") ;
532                 }
533
534                 len = ntohl(request.len);
535
536                 if (request.magic != htonl(NBD_REQUEST_MAGIC))
537                         err("Not enough magic.");
538                 if (len > BUFSIZE)
539                         err("Request too big!");
540 #ifdef DODBG
541                 printf("%s from %Lu (%Lu) len %d, ", request.type ? "WRITE" :
542                                 "READ", (unsigned long long)request.from,
543                                 (unsigned long long)request.from / 512, len);
544 #endif
545                 memcpy(reply.handle, request.handle, sizeof(reply.handle));
546                 if ((request.from + len) > (OFFT_MAX)) {
547                   DEBUG("[Number too large!]");
548                   ERROR;
549                   continue;
550                 }
551                 if ((((off_t)request.from + len) > exportsize) ||
552                     ((flags & F_READONLY) && request.type)) {
553                         DEBUG("[RANGE!]");
554                         ERROR;
555                         continue;
556                 }
557                 if (request.type==1) {  /* WRITE */
558                         DEBUG("wr: net->buf, ");
559                         readit(net, buf, len);
560                         DEBUG("buf->exp, ");
561                         if ((autoreadonly == 1) || expwrite(request.from, buf, len)) {
562                                 DEBUG("Write failed: %m" );
563                                 ERROR;
564                                 continue;
565                         }
566                         lastpoint += len;
567                         SEND;
568                         DEBUG("OK!\n");
569                         continue;
570                 }
571                 /* READ */
572
573                 DEBUG("exp->buf, ");
574                 if (expread(request.from, buf + sizeof(struct nbd_reply), len)) {
575                         lastpoint = -1;
576                         DEBUG("Read failed: %m");
577                         ERROR;
578                         continue;
579                 }
580                 lastpoint += len;
581
582                 DEBUG("buf->net, ");
583                 memcpy(buf, &reply, sizeof(struct nbd_reply));
584                 writeit(net, buf, len + sizeof(struct nbd_reply));
585                 DEBUG("OK!\n");
586         }
587 }
588
589 char exportname2[1024];
590
591 void set_peername(int net,char *clientname)
592 {
593         struct sockaddr_in addrin;
594         int addrinlen = sizeof( addrin );
595         char *peername ;
596
597         if (getpeername( net, (struct sockaddr *) &addrin, &addrinlen ) < 0)
598                 err("getsockname failed: %m");
599         peername = inet_ntoa(addrin.sin_addr);
600         sprintf(exportname2, exportname, peername);
601
602         msg4(LOG_INFO, "connect from %s, assigned file is %s", peername, exportname2);
603         strncpy(clientname,peername,255) ;
604 }
605
606 off_t size_autodetect(int export)
607 {
608         off_t es;
609         u32 es32;
610         struct stat stat_buf;
611         int error;
612         
613         DEBUG("looking for export size with lseek SEEK_END\n");
614         es = lseek(export, (off_t)0, SEEK_END);
615         if (es > ((off_t)0)) {
616                 return es;
617         } else {
618                 DEBUG2("lseek failed: %d", errno==EBADF?1:(errno==ESPIPE?2:(errno==EINVAL?3:4)));
619         }
620         
621         DEBUG("looking for export size with fstat\n");
622         stat_buf.st_size = 0;
623         error = fstat(export, &stat_buf);
624         if (!error && stat_buf.st_size > 0) {
625                 return (off_t)stat_buf.st_size;
626         } else {
627                 err("fstat failed: %m");
628         }
629         
630 #ifdef BLKGETSIZE
631         DEBUG("looking for export size with ioctl BLKGETSIZE\n");
632         if (!ioctl(export, BLKGETSIZE, &es32) && es32) {
633                 es = (off_t)es32 * (off_t)512;
634                 return es;
635         }
636 #endif
637         err("Could not find size of exported block device: %m");
638         return OFFT_MAX;
639 }
640
641 int main(int argc, char *argv[])
642 {
643         int net;
644         off_t i;
645
646         if (sizeof( struct nbd_request )!=28) {
647                 fprintf(stderr,"Bad size of structure. Alignment problems?\n");
648                 exit(-1) ;
649         }
650         logging();
651         cmdline(argc, argv);
652         
653         if (!port) return 1 ;
654         connectme(port); /* serve infinitely */
655         return 0 ;
656 }
657
658
659 void serveconnection(int net) 
660 {   
661         off_t i ;
662         
663         for (i=0; i<exportsize; i+=hunksize) {
664                 char exportname3[1024];
665                 
666                 sprintf(exportname3, exportname2, i/hunksize);
667                 printf( "Opening %s\n", exportname3 );
668                 if ((export[i/hunksize] = open(exportname3, (flags & F_READONLY) ? O_RDONLY : O_RDWR)) == -1) {
669                         /* Read WRITE ACCESS was requested by media is only read only */
670                         autoreadonly = 1;
671                         flags |= F_READONLY;
672                         if ((export[i/hunksize] = open(exportname3, O_RDONLY)) == -1) 
673                                 err("Could not open exported file: %m");
674                 }
675         }
676         
677         if (exportsize == (off_t)OFFT_MAX) {
678                 exportsize = size_autodetect(export[0]);
679         }
680         if (exportsize > (off_t)OFFT_MAX) {
681                 err("Size of exported file is too big\n");
682         }
683         else
684                 msg3(LOG_INFO, "size of exported file/device is %Lu",
685                      (unsigned long long)exportsize);
686         
687         if (flags & F_COPYONWRITE) {
688                 sprintf(difffilename,"%s-%s-%d.diff",exportname2,clientname,
689                         (int)getpid()) ;
690                 msg3(LOG_INFO,"About to create map and diff file %s",difffilename) ;
691                 difffile=open(difffilename,O_RDWR | O_CREAT | O_TRUNC,0600) ;
692                 if (difffile<0) err("Could not create diff file (%m)") ;
693                 if ((difmap=calloc(exportsize/DIFFPAGESIZE,sizeof(u32)))==NULL)
694                         err("Could not allocate memory") ;
695                 for (i=0;i<exportsize/DIFFPAGESIZE;i++) difmap[i]=(u32)-1 ;       
696         }
697         
698         setmysockopt(net);
699         
700         mainloop(net);
701 }