r35: Added an option to allow for selecting the .allow file on the command
[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                 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 }