r49: Doxygenified the source, and started modularizing it. Lots of work
[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 2001-2004 Wouter Verhelst <wouter@debian.org>
7  * Copyright 2002 Anton Altaparmakov <aia21@cam.ac.uk>
8  *
9  * Version 1.0 - hopefully 64-bit-clean
10  * Version 1.1 - merging enhancements from Josh Parsons, <josh@coombs.anu.edu.au>
11  * Version 1.2 - autodetect size of block devices, thanx to Peter T. Breuer" <ptb@it.uc3m.es>
12  * Version 1.5 - can compile on Unix systems that don't have 64 bit integer
13  *      type, or don't have 64 bit file offsets by defining FS_32BIT
14  *      in compile options for nbd-server *only*. This can be done
15  *      with make FSCHOICE=-DFS_32BIT nbd-server. (I don't have the
16  *      original autoconf input file, or I would make it a configure
17  *      option.) Ken Yap <ken@nlc.net.au>.
18  * Version 1.6 - fix autodetection of block device size and really make 64 bit
19  *      clean on 32 bit machines. Anton Altaparmakov <aia21@cam.ac.uk>
20  * Version 2.0 - Version synchronised with client
21  * Version 2.1 - Reap zombie client processes when they exit. Removed
22  *      (uncommented) the _IO magic, it's no longer necessary. Wouter
23  *      Verhelst <wouter@debian.org>
24  * Version 2.2 - Auto switch to read-only mode (usefull for floppies).
25  * Version 2.3 - Fixed code so that Large File Support works. This
26  *      removes the FS_32BIT compile-time directive; define
27  *      _FILE_OFFSET_BITS=64 and _LARGEFILE_SOURCE if you used to be
28  *      using FS_32BIT. This will allow you to use files >2GB instead of
29  *      having to use the -m option. Wouter Verhelst <wouter@debian.org>
30  * Version 2.4 - Added code to keep track of children, so that we can
31  *      properly kill them from initscripts. Add a call to daemon(),
32  *      so that processes don't think they have to wait for us, which is
33  *      interesting for initscripts as well. Wouter Verhelst
34  *      <wouter@debian.org>
35  * Version 2.5 - Bugfix release: forgot to reset child_arraysize to
36  *      zero after fork()ing, resulting in nbd-server going berserk
37  *      when it receives a signal with at least one child open. Wouter
38  *      Verhelst <wouter@debian.org>
39  * 10/10/2003 - Added socket option SO_KEEPALIVE (sf.net bug 819235);
40  *      rectified type of mainloop::size_host (sf.net bugs 814435 and
41  *      817385); close the PID file after writing to it, so that the
42  *      daemon can actually be found. Wouter Verhelst
43  *      <wouter@debian.org>
44  * 10/10/2003 - Size of the data "size_host" was wrong and so was not
45  *      correctly put in network endianness. Many types were corrected
46  *      (size_t and off_t instead of int).  <vspaceg@sourceforge.net>
47  * Version 2.6 - Some code cleanup.
48  * Version 2.7 - Better build system (not released (yet?)).
49  * 11/02/2004 - Doxygenified the source, modularized it a bit. Needs a 
50  *      lot more work, but this is a start. Wouter Verhelst
51  *      <wouter@debian.org>
52  */
53
54 #include <sys/types.h>
55 #include <sys/socket.h>
56 #include <sys/stat.h>
57 #include <sys/wait.h>           /* wait */
58 #include <sys/ioctl.h>
59 #include <sys/param.h>
60 #include <sys/mount.h>          /* For BLKGETSIZE */
61 #include <signal.h>             /* sigaction */
62 #include <netinet/tcp.h>
63 #include <netinet/in.h>         /* sockaddr_in, htons, in_addr */
64 #include <netdb.h>              /* hostent, gethostby*, getservby* */
65 #include <syslog.h>
66 #include <unistd.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <fcntl.h>
71 #include <arpa/inet.h>
72 #include <strings.h>
73 #include <dirent.h>
74
75 /* used in cliserv.h, so must come first */
76 #define MY_NAME "nbd_server"
77 #include "cliserv.h"
78
79 /** how much space for child PIDs we have by default. Dynamically
80    allocated, and will be realloc()ed if out of space, so this should
81    probably be fair for most situations. */
82 #define DEFAULT_CHILD_ARRAY 256
83
84 /** Logging macros, now nothing goes to syslog unless you say ISSERVER */
85 #ifdef ISSERVER
86 #define msg2(a,b) syslog(a,b)
87 #define msg3(a,b,c) syslog(a,b,c)
88 #define msg4(a,b,c,d) syslog(a,b,c,d)
89 #else
90 #define msg2(a,b) do { fprintf(stderr,b) ; fputs("\n",stderr) ; } while(0) 
91 #define msg3(a,b,c) do { fprintf(stderr,b,c); fputs("\n",stderr) ; } while(0) 
92 #define msg4(a,b,c,d) do { fprintf(stderr,b,c,d); fputs("\n",stderr) ; } while(0)
93 #endif
94
95 /* Debugging macros */
96 //#define DODBG
97 #ifdef DODBG
98 #define DEBUG( a ) printf( a )
99 #define DEBUG2( a,b ) printf( a,b )
100 #define DEBUG3( a,b,c ) printf( a,b,c )
101 #else
102 #define DEBUG( a )
103 #define DEBUG2( a,b ) 
104 #define DEBUG3( a,b,c ) 
105 #endif
106 /** sending macro... not really required */
107 #define SEND writeit( net, &reply, sizeof( reply ));
108 /** error macro... not sure whether we really need this */
109 #define ERROR { reply.error = htonl(-1); SEND; reply.error = 0; lastpoint = -1; }
110 #ifndef PACKAGE_VERSION
111 #define PACKAGE_VERSION ""
112 #endif
113 /**
114  * The highest value a variable of type off_t can reach.
115  **/
116 /* This is starting to get ugly. If someone knows a better way to find
117  * the maximum value of a signed type *without* relying on overflow
118  * (doing so breaks on 64bit architectures), that would be nice.
119  */
120 #define OFFT_MAX (((((off_t)1)<<((sizeof(off_t)-1)*8))-1)<<7)+127
121 #define LINELEN 256       /**< Size of static buffer used to read the
122                             authorization file (yuck) */
123 #define BUFSIZE (1024*1024) /**< Size of buffer that can hold requests */
124 #define GIGA (1*1024*1024*1024) /**< 1 Gigabyte. Used as hunksize when doing
125                                   the multiple file thingy */
126 #define DIFFPAGESIZE 4096 /**< diff file uses those chunks */
127 #define F_READONLY 1      /**< flag to tell us a file is readonly */
128 #define F_MULTIFILE 2     /**< flag to tell us a file is exported using -m */
129 #define F_COPYONWRITE 4   /**< flag to tell us a file is exported using copyonwrite */
130 char difffilename[256]; /**< filename of the copy-on-write file. Doesn't belong here! */
131 unsigned int timeout = 0; /**< disconnect timeout */
132 int autoreadonly = 0; /**< 1 = switch to readonly if opening readwrite isn't
133                         possible */
134 char *auth_file="nbd_server.allow"; /**< authorization file */
135 char exportname2[1024]; /**< File I'm exporting, with virtualhost resolved */
136 off_t lastpoint = (off_t)-1;    /**< keep track of where we are in the file, to
137                                   avoid an lseek if possible */
138 char pagebuf[DIFFPAGESIZE];     /**< when doing copyonwrite, this is
139                                   used as a temporary buffer to store
140                                   the exported block in. @todo this is
141                                   a great example of namespace
142                                   pollution. Throw it out. */
143 unsigned int port;              /**< Port I'm listening at */
144 char *exportname;               /**< File I'm exporting */
145 off_t exportsize = OFFT_MAX;    /**< length of file I'm exporting */
146 off_t hunksize = OFFT_MAX;      /**< size of each exported file in case of -m */
147 int flags = 0;                  /**< flags associated with this exported file */
148 int export[1024];/**< array of filedescriptors of exported files; only first is
149                    used unless -m option is activated */ 
150 int difffile=-1; /**< filedescriptor for copyonwrite file */
151 u32 difffilelen=0 ; /**< number of pages in difffile */
152 u32 *difmap=NULL ; /**< Determine whether a block is in the original file
153                      (difmap[block]==-1) or in the copyonwrite file (in which
154                      case it contains the offset where it is to be found in the
155                      copyonwrite file). @todo the kernel knows about sparse
156                      files, we should use those instead. Should also be off_t
157                      instead of u32; copyonwrite is probably broken wrt LFS */
158 char clientname[256] ;
159 int child_arraysize=DEFAULT_CHILD_ARRAY; /**< number of available slots for
160                                            child array */
161 pid_t *children; /**< child array */
162 char pidfname[256]; /**< name of our PID file */
163
164 /**
165  * Variables associated with a copyonwrite server. Not yet used.
166  **/
167 typedef struct __cow_opts {
168         char* difffilename;  /**< filename of the copy-on-write file */
169         int difffile;        /**< filedescriptor of copyonwrite file. @todo
170                                shouldn't this be an array too? (cfr
171                                nbd_server_opts::export) Or make -m and -c
172                                mutually exclusive */
173         u32 difffilelen;     /**< number of pages in difffile */
174         u32 *difmap;         /**< see comment on the global difmap for this one */
175 } cow_opts;
176
177 /**
178  * Variables associated with a server. Not yet used.
179  **/
180 typedef struct __nbd_server_opts {
181         char* exportname;    /**< filename of the file we're exporting */
182         unsigned int port;            /**< port we're exporting this file at */
183         char* authname;      /**< filename of the authorization file */
184         off_t exportsize;    /**< size of the file we're exporting */
185         off_t hunksize;      /**< size of a hunk of an exported file */
186         int flags;           /**< flags associated with this exported file */
187         char* clientname;          /**< peer */
188         unsigned int timeout;/**< how long a connection may be idle
189                                (0=forever) */
190         int export[1024];    /**< array of filedescriptors of exported files;
191                                only the first is actually used unless we're
192                                doing the multiple file option */
193         cow_opts* cow;       /**< only used if (flags | F_COPYONWRITE) */
194 } nbd_server_opts;
195
196 /**
197  * Check whether a client is allowed to connect. Works with an
198  * authorization file which contains one line per machine, no
199  * wildcards.
200  * @param name IP address of client trying to connect (in human-readable form)
201  * @return 0 - authorization refused, 1 - OK
202  **/
203 int authorized_client(char *name)
204 {
205         FILE *f ;
206    
207         char line[LINELEN] ; 
208
209         if ((f=fopen(auth_file,"r"))==NULL) {
210                 msg4(LOG_INFO,"Can't open authorization file %s (%s).",
211                      auth_file,strerror(errno)) ;
212                 return 1 ; 
213         }
214   
215         while (fgets(line,LINELEN,f)!=NULL) {
216                 if (strncmp(line,name,strlen(name))==0) {
217                         fclose(f);
218                         return 1;
219                 }
220         }
221         fclose(f) ;
222         return 0 ;
223 }
224
225 /**
226  * Read data from a file descriptor into a buffer
227  *
228  * @param f a file descriptor
229  * @param buf a buffer
230  * @param len the number of bytes to be read
231  **/
232 inline void readit(int f, void *buf, size_t len)
233 {
234         ssize_t res;
235         while (len > 0) {
236                 DEBUG("*");
237                 if ((res = read(f, buf, len)) <= 0)
238                         err("Read failed: %m");
239                 len -= res;
240                 buf += res;
241         }
242 }
243
244 /**
245  * Write data from a buffer into a filedescriptor
246  *
247  * @param f a file descriptor
248  * @param buf a buffer containing data
249  * @param len the number of bytes to be written
250  **/
251 inline void writeit(int f, void *buf, size_t len)
252 {
253         ssize_t res;
254         while (len > 0) {
255                 DEBUG("+");
256                 if ((res = write(f, buf, len)) <= 0)
257                         err("Send failed: %m");
258                 len -= res;
259                 buf += res;
260         }
261 }
262
263 /**
264  * Parse the command line.
265  *
266  * @todo getopt() is a great thing, and easy to use. Also, we want to
267  * create a configuration file which nbd-server will read.
268  *
269  * @param argc the argc argument to main()
270  * @param argv the argv argument to main()
271  **/
272 void cmdline(int argc, char *argv[])
273 {
274         int i;
275
276         if (argc < 3) {
277                 printf("This is nbd-server version " VERSION "\n");     
278                 printf("Usage: port file_to_export [size][kKmM] [-r] [-m] [-c] [-a timeout_sec]\n"
279                        "        -r read only\n"
280                        "        -m multiple file\n"
281                        "        -c copy on write\n"
282                        "        -l file with list of hosts that are allowed to connect.\n"
283                        "        -a maximum idle seconds, terminates when idle time exceeded\n"
284                        "        if port is set to 0, stdin is used (for running from inetd)\n"
285                        "        if file_to_export contains '%%s', it is substituted with IP\n"
286                        "                address of machine trying to connect\n" );
287                 exit(0);
288         }
289         port = atoi(argv[1]);
290         for (i = 3; i < argc; i++) {
291                 if (*argv[i] == '-') {
292                         switch (argv[i][1]) {
293                         case 'r':
294                                 flags |= F_READONLY;
295                                 break;
296                         case 'm':
297                                 flags |= F_MULTIFILE;
298                                 hunksize = 1*GIGA;
299                                 break;
300                         case 'c': flags |=F_COPYONWRITE;
301                                 break;
302                         case 'l':
303                                 free(auth_file);
304                                 if (i+1<argc) {
305                                         auth_file=argv[++i];
306                                 } else {
307                                         fprintf(stderr, "host list file requires an argument");
308                                 }
309                                 break;
310                         case 'a': 
311                                 if (i+1<argc) {
312                                         timeout = atoi(argv[i+1]);
313                                         i++;
314                                 } else {
315                                         fprintf(stderr, "timeout requires argument\n");
316                                         exit(1);
317                                 }
318                         }
319                 } else {
320                         off_t es;
321                         size_t last = strlen(argv[i])-1;
322                         char suffix = argv[i][last];
323                         if (suffix == 'k' || suffix == 'K' ||
324                             suffix == 'm' || suffix == 'M')
325                                 argv[i][last] = '\0';
326                         es = (off_t)atol(argv[i]);
327                         switch (suffix) {
328                                 case 'm':
329                                 case 'M':  es <<= 10;
330                                 case 'k':
331                                 case 'K':  es <<= 10;
332                                 default :  break;
333                         }
334                         exportsize = es;
335                 }
336         }
337
338         exportname = argv[2];
339 }
340
341 /**
342  * Signal handler for SIGCHLD
343  * @param s the signal we're handling (must be SIGCHLD, or something
344  * is severely wrong)
345  **/
346 void sigchld_handler(int s)
347 {
348         int* status=NULL;
349         int i;
350         pid_t pid;
351
352         while((pid=wait(status)) > 0) {
353                 if(WIFEXITED(status)) {
354                         msg3(LOG_INFO, "Child exited with %d", WEXITSTATUS(status));
355                 }
356                 for(i=0;children[i]!=pid&&i<child_arraysize;i++);
357                 if(i>=child_arraysize) {
358                         msg3(LOG_INFO, "SIGCHLD received for an unknown child with PID %ld",(long) pid);
359                 } else {
360                         children[i]=(pid_t)0;
361                         DEBUG2("Removing %d from the list of children", pid);
362                 }
363         }
364 }
365
366 /**
367  * Handle SIGTERM and dispatch it to our children
368  * @param s the signal we're handling (must be SIGTERM, or something
369  * is severely wrong).
370  **/
371 void sigterm_handler(int s) {
372         int i;
373         int parent=0;
374
375         for(i=0;i<child_arraysize;i++) {
376                 if(children[i]) {
377                         kill(children[i], s);
378                         parent=1;
379                 }
380         }
381
382         if(parent) {
383                 unlink(pidfname);
384         }
385                 
386         exit(0);
387 }
388
389 /**
390  * Detect the size of a file.
391  *
392  * @param export An open filedescriptor
393  * @return the size of the file, or OFFT_MAX if detection was
394  * impossible.
395  **/
396 off_t size_autodetect(int export)
397 {
398         off_t es;
399         u32 es32;
400         struct stat stat_buf;
401         int error;
402         
403         DEBUG("looking for export size with lseek SEEK_END\n");
404         es = lseek(export, (off_t)0, SEEK_END);
405         if (es > ((off_t)0)) {
406                 return es;
407         } else {
408                 DEBUG2("lseek failed: %d", errno==EBADF?1:(errno==ESPIPE?2:(errno==EINVAL?3:4)));
409         }
410         
411         DEBUG("looking for export size with fstat\n");
412         stat_buf.st_size = 0;
413         error = fstat(export, &stat_buf);
414         if (!error && stat_buf.st_size > 0) {
415                 return (off_t)stat_buf.st_size;
416         } else {
417                 err("fstat failed: %m");
418         }
419         
420 #ifdef BLKGETSIZE
421         DEBUG("looking for export size with ioctl BLKGETSIZE\n");
422         if (!ioctl(export, BLKGETSIZE, &es32) && es32) {
423                 es = (off_t)es32 * (off_t)512;
424                 return es;
425         }
426 #endif
427         err("Could not find size of exported block device: %m");
428         return OFFT_MAX;
429 }
430
431 /**
432  * Seek to a position in a file, unless we're already there.
433  * @param handle a filedescriptor
434  * @param a position to seek to
435  **/
436 void maybeseek(int handle, off_t a) {
437         if (a < 0 || a > exportsize) {
438                 err("Can not happen\n");
439         }
440         if (lastpoint != a) {
441                 if (lseek(handle, a, SEEK_SET) < 0) {
442                         err("Can not seek locally!\n");
443                 }
444                 lastpoint = a;
445         } else {
446                 DEBUG("S");
447         }
448 }
449
450 /**
451  * Write an amount of bytes at a given offset to the right file. This
452  * abstracts the write-side of the multiple file option.
453  *
454  * @param a The offset where the write should start
455  * @param buf The buffer to write from
456  * @param len The length of buf
457  * @return The number of bytes actually written, or -1 in case of an error
458  **/
459 int rawexpwrite(off_t a, char *buf, size_t len)
460 {
461         ssize_t res;
462
463         maybeseek(export[a/hunksize], a%hunksize);
464         res = write(export[a/hunksize], buf, len);
465         return (res < 0 || (size_t)res != len);
466 }
467
468 /**
469  * seek to a position in a file, no matter what. Used when using maybeseek is a
470  * bad idea (for instance, because we're reading the copyonwrite file instead
471  * of the exported file)
472  * @param handle a filedescriptor
473  * @param a position to seek to
474  **/
475 void myseek(int handle,off_t a) {
476         if (lseek(handle, a, SEEK_SET) < 0) {
477                 err("Can not seek locally!\n");
478         }
479 }
480
481 /**
482  * Read an amount of bytes at a given offset from the right file. This
483  * abstracts the read-side of the multiple files option.
484  *
485  * @param a The offset where the read should start
486  * @param buf A buffer to read into
487  * @param len The size of buf
488  * @return The number of bytes actually read, or -1 in case of an
489  * error.
490  **/
491 int rawexpread(off_t a, char *buf, size_t len)
492 {
493         ssize_t res;
494
495         maybeseek(export[a/hunksize], a%hunksize);
496         res = read(export[a/hunksize], buf, len);
497         return (res < 0 || (size_t)res != len);
498 }
499
500 /**
501  * Read an amount of bytes at a given offset from the right file. This
502  * abstracts the read-side of the copyonwrite stuff, and calls
503  * rawexpread() with the right parameters to do the actual work.
504  * @param a The offset where the read should start
505  * @param buf A buffer to read into
506  * @param len The size of buf
507  * @return The number of bytes actually read, or -1 in case of an error
508  **/
509 int expread(off_t a, char *buf, size_t len)
510 {
511         off_t rdlen, offset;
512         off_t mapcnt, mapl, maph, pagestart;
513  
514         if (!(flags & F_COPYONWRITE))
515                 return rawexpread(a, buf, len);
516         DEBUG3("Asked to read %d bytes at %Lu.\n", len, (unsigned long long)a);
517
518         mapl=a/DIFFPAGESIZE; maph=(a+len-1)/DIFFPAGESIZE;
519
520         for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
521                 pagestart=mapcnt*DIFFPAGESIZE;
522                 offset=a-pagestart;
523                 rdlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
524                         len : (size_t)DIFFPAGESIZE-offset;
525                 if (difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
526                         DEBUG3("Page %Lu is at %lu\n", (unsigned long long)mapcnt,
527                                (unsigned long)difmap[mapcnt]);
528                         myseek(difffile, difmap[mapcnt]*DIFFPAGESIZE+offset);
529                         if (read(difffile, buf, rdlen) != rdlen) return -1;
530                 } else { /* the block is not there */
531                         DEBUG2("Page %Lu is not here, we read the original one\n",
532                                (unsigned long long)mapcnt);
533                         return rawexpread(a, buf, rdlen);
534                 }
535                 len-=rdlen; a+=rdlen; buf+=rdlen;
536         }
537         return 0;
538 }
539
540 /**
541  * Write an amount of bytes at a given offset to the right file. This
542  * abstracts the write-side of the copyonwrite option, and calls
543  * rawexpwrite() with the right parameters to do the actual work.
544  *
545  * @param a The offset where the write should start
546  * @param buf The buffer to write from
547  * @param len The length of buf
548  * @return The number of bytes actually written, or -1 in case of an error
549  **/
550 int expwrite(off_t a, char *buf, size_t len)
551 {
552         off_t mapcnt,mapl,maph ;
553         off_t wrlen,rdlen ; 
554         off_t pagestart ;
555         off_t offset ;
556
557         if (!(flags & F_COPYONWRITE))
558                 return(rawexpwrite(a,buf,len)); 
559         DEBUG3("Asked to write %d bytes at %Lu.\n", len, (unsigned long long)a);
560
561         mapl=a/DIFFPAGESIZE ; maph=(a+len-1)/DIFFPAGESIZE ;
562
563         for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
564                 pagestart=mapcnt*DIFFPAGESIZE ;
565                 offset=a-pagestart ;
566                 wrlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
567                         len : (size_t)DIFFPAGESIZE-offset;
568
569                 if (difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
570                         DEBUG3("Page %Lu is at %lu\n", (unsigned long long)mapcnt,
571                                (unsigned long)difmap[mapcnt]) ;
572                         myseek(difffile,difmap[mapcnt]*DIFFPAGESIZE+offset) ;
573                         if (write(difffile, buf, wrlen) != wrlen) return -1 ;
574                 } else { /* the block is not there */
575                         myseek(difffile,difffilelen*DIFFPAGESIZE) ;
576                         difmap[mapcnt]=difffilelen++ ;
577                         DEBUG3("Page %Lu is not here, we put it at %lu\n",
578                                (unsigned long long)mapcnt,
579                                (unsigned long)difmap[mapcnt]);
580                         rdlen=DIFFPAGESIZE ;
581                         if (rdlen+pagestart%hunksize>hunksize) 
582                                 rdlen=hunksize-(pagestart%hunksize) ;
583                         if (rawexpread(pagestart,pagebuf,rdlen)) return -1 ;
584                         memcpy(pagebuf+offset,buf,wrlen) ;
585                         if (write(difffile,pagebuf,DIFFPAGESIZE)!=DIFFPAGESIZE) return -1 ;
586                 }                                                   
587                 len-=wrlen ; a+=wrlen ; buf+=wrlen ;
588         }
589         return 0;
590 }
591
592 /**
593  * Do the initial negotiation.
594  *
595  * @param net A socket to do the negotiation over
596  **/
597 void negotiate(int net) {
598         char zeros[300];
599         u64 size_host;
600
601         memset(zeros, 0, 290);
602         if (write(net, INIT_PASSWD, 8) < 0)
603                 err("Negotiation failed: %m");
604         cliserv_magic = htonll(cliserv_magic);
605         if (write(net, &cliserv_magic, sizeof(cliserv_magic)) < 0)
606                 err("Negotiation failed: %m");
607         size_host = htonll((u64)exportsize);
608         if (write(net, &size_host, 8) < 0)
609                 err("Negotiation failed: %m");
610         if (write(net, zeros, 128) < 0)
611                 err("Negotiation failed: %m");
612 }
613
614 /**
615  * Serve a file to a single client.
616  *
617  * @todo This beast needs to be split up in many tiny little manageable
618  * pieces. Preferably with a chainsaw.
619  *
620  * @param net A network socket, connected to an nbd client
621  * @return never
622  **/
623 int mainloop(int net)
624 {
625         struct nbd_request request;
626         struct nbd_reply reply;
627 #ifdef DODBG
628         int i = 0;
629 #endif
630         negotiate(net);
631         DEBUG("Entering request loop!\n");
632         reply.magic = htonl(NBD_REPLY_MAGIC);
633         reply.error = 0;
634         while (1) {
635                 char buf[BUFSIZE];
636                 size_t len;
637 #ifdef DODBG
638                 i++;
639                 printf("%d: ", i);
640 #endif
641                 if (timeout) 
642                         alarm(timeout);
643                 readit(net, &request, sizeof(request));
644                 request.from = ntohll(request.from);
645                 request.type = ntohl(request.type);
646
647                 if (request.type==NBD_CMD_DISC) { /* Disconnect request */
648                   if (difmap) free(difmap) ;
649                   if (difffile>=0) { 
650                      close(difffile) ; unlink(difffilename) ; }
651                   err("Disconnect request received.") ;
652                 }
653
654                 len = ntohl(request.len);
655
656                 if (request.magic != htonl(NBD_REQUEST_MAGIC))
657                         err("Not enough magic.");
658                 if (len > BUFSIZE)
659                         err("Request too big!");
660 #ifdef DODBG
661                 printf("%s from %Lu (%Lu) len %d, ", request.type ? "WRITE" :
662                                 "READ", (unsigned long long)request.from,
663                                 (unsigned long long)request.from / 512, len);
664 #endif
665                 memcpy(reply.handle, request.handle, sizeof(reply.handle));
666                 if ((request.from + len) > (OFFT_MAX)) {
667                   DEBUG("[Number too large!]");
668                   ERROR;
669                   continue;
670                 }
671
672                 if (((ssize_t)((off_t)request.from + len) > exportsize) ||
673                     ((flags & F_READONLY) && request.type)) {
674                         DEBUG("[RANGE!]");
675                         ERROR;
676                         continue;
677                 }
678
679                 if (request.type==1) {  /* WRITE */
680                         DEBUG("wr: net->buf, ");
681                         readit(net, buf, len);
682                         DEBUG("buf->exp, ");
683                         if ((autoreadonly == 1) || expwrite(request.from, buf, len)) {
684                                 DEBUG("Write failed: %m" );
685                                 ERROR;
686                                 continue;
687                         }
688                         lastpoint += len;
689                         SEND;
690                         DEBUG("OK!\n");
691                         continue;
692                 }
693                 /* READ */
694
695                 DEBUG("exp->buf, ");
696                 if (expread(request.from, buf + sizeof(struct nbd_reply), len)) {
697                         lastpoint = -1;
698                         DEBUG("Read failed: %m");
699                         ERROR;
700                         continue;
701                 }
702                 lastpoint += len;
703
704                 DEBUG("buf->net, ");
705                 memcpy(buf, &reply, sizeof(struct nbd_reply));
706                 writeit(net, buf, len + sizeof(struct nbd_reply));
707                 DEBUG("OK!\n");
708         }
709 }
710
711 /**
712  * Split a single exportfile into multiple ones, if that was asked.
713  * @return 0 on success, -1 on failure
714  **/
715 int splitexport(void) {
716         off_t i ;
717         
718         for (i=0; i<exportsize; i+=hunksize) {
719                 char exportname3[1024];
720                 
721                 sprintf(exportname3, exportname2, i/hunksize);
722                 printf( "Opening %s\n", exportname3 );
723                 if ((export[i/hunksize] = open(exportname3, (flags & F_READONLY) ? O_RDONLY : O_RDWR)) == -1) {
724                         /* Read WRITE ACCESS was requested by media is only read only */
725                         autoreadonly = 1;
726                         flags |= F_READONLY;
727                         if ((export[i/hunksize] = open(exportname3, O_RDONLY)) == -1) 
728                                 err("Could not open exported file: %m");
729                 }
730         }
731
732         if (flags & F_COPYONWRITE) {
733                 sprintf(difffilename,"%s-%s-%d.diff",exportname2,clientname,
734                         (int)getpid()) ;
735                 msg3(LOG_INFO,"About to create map and diff file %s",difffilename) ;
736                 difffile=open(difffilename,O_RDWR | O_CREAT | O_TRUNC,0600) ;
737                 if (difffile<0) err("Could not create diff file (%m)") ;
738                 if ((difmap=calloc(exportsize/DIFFPAGESIZE,sizeof(u32)))==NULL)
739                         err("Could not allocate memory") ;
740                 for (i=0;i<exportsize/DIFFPAGESIZE;i++) difmap[i]=(u32)-1 ;
741         }
742
743         return 0;
744 }
745
746 /**
747  * Serve a connection. 
748  *
749  * @todo allow for multithreading, perhaps use libevent.
750  *
751  * @param net A network socket connected to an nbd client
752  **/
753 void serveconnection(int net) {   
754         splitexport();
755         if (exportsize == OFFT_MAX) {
756                 exportsize = size_autodetect(export[0]);
757         }
758         if (exportsize > OFFT_MAX) {
759                 err("Size of exported file is too big\n");
760         }
761         else
762                 msg3(LOG_INFO, "size of exported file/device is %Lu",
763                      (unsigned long long)exportsize);
764
765         setmysockopt(net);
766
767         mainloop(net);
768 }
769
770 /**
771  * Find the name of the file we have to serve. This will use sprintf()
772  * to put the IP address of the client inside a filename containing
773  * "%s". That name is then written to exportname2
774  *
775  * @param net A socket connected to an nbd client
776  * @param clientname a buffer which must be at least 255+1 bytes long;
777  * the IP address (in human-readable format) will be copied in there.
778  **/
779 void set_peername(int net,char *clientname)
780 {
781         struct sockaddr_in addrin;
782         int addrinlen = sizeof( addrin );
783         char *peername ;
784
785         if (getpeername( net, (struct sockaddr *) &addrin, &addrinlen ) < 0)
786                 err("getsockname failed: %m");
787         peername = inet_ntoa(addrin.sin_addr);
788         sprintf(exportname2, exportname, peername);
789
790         msg4(LOG_INFO, "connect from %s, assigned file is %s", 
791              peername, exportname2);
792         strncpy(clientname,peername,255) ;
793 }
794
795 /**
796  * Connect the socket, and start to serve. This function will fork()
797  * if a connection from an authorized client is received, and will
798  * start mainloop().
799  *
800  * @todo modularize this giant beast. Preferably with a chainsaw. Also,
801  * it has no business starting mainloop(); it should connect, and be
802  * done with it.
803  *
804  * @param port the port where we will listen
805  **/
806 void connectme(unsigned int port)
807 {
808         struct sockaddr_in addrin;
809         struct sigaction sa;
810         int addrinlen = sizeof(addrin);
811         int net, sock, newpid, i;
812 #ifndef sun
813         int yes=1;
814 #else
815         char yes='1';
816 #endif /* sun */
817 #ifndef NODAEMON
818 #ifndef NOFORK
819         FILE*pidf;
820
821         if(port) {
822                 if(daemon(0,0)<0) {
823                         err("daemon");
824                 }
825                 snprintf(pidfname, sizeof(char)*255, "/var/run/nbd-server.%d.pid", port);
826                 pidf=fopen(pidfname, "w");
827                 if(pidf) {
828                         fprintf(pidf,"%d", (int)getpid());
829                         fclose(pidf);
830                 } else {
831                         perror("fopen");
832                         fprintf(stderr, "Not fatal; continuing");
833                 }
834         }
835 #endif /* NOFORK */
836 #endif /* NODAEMON */
837
838         if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
839                 err("socket: %m");
840
841         /* lose the pesky "Address already in use" error message */
842         if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
843                 err("setsockopt SO_REUSEADDR");
844         }
845         if (setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,&yes,sizeof(int)) == -1) {
846                 err("setsockopt SO_KEEPALIVE");
847         }
848
849         DEBUG("Waiting for connections... bind, ");
850         addrin.sin_family = AF_INET;
851         addrin.sin_port = htons(port);
852         addrin.sin_addr.s_addr = 0;
853         if (bind(sock, (struct sockaddr *) &addrin, addrinlen) < 0)
854                 err("bind: %m");
855         DEBUG("listen, ");
856         if (listen(sock, 1) < 0)
857                 err("listen: %m");
858         DEBUG("accept, ");
859         sa.sa_handler = sigchld_handler;
860         sigemptyset(&sa.sa_mask);
861         sa.sa_flags = SA_RESTART;
862         if(sigaction(SIGCHLD, &sa, NULL) == -1)
863                 err("sigaction: %m");
864         sa.sa_handler = sigterm_handler;
865         sigemptyset(&sa.sa_mask);
866         sa.sa_flags = SA_RESTART;
867         if(sigaction(SIGTERM, &sa, NULL) == -1)
868                 err("sigaction: %m");
869         children=malloc(sizeof(pid_t)*child_arraysize);
870         memset(children, 0, sizeof(pid_t)*DEFAULT_CHILD_ARRAY);
871         for(;;) { /* infinite loop */
872                 if ((net = accept(sock, (struct sockaddr *) &addrin, &addrinlen)) < 0)
873                         err("accept: %m");
874                 
875                 set_peername(net,clientname);
876                 if (!authorized_client(clientname)) {
877                         msg2(LOG_INFO,"Unauthorized client") ;
878                         close(net) ;
879                         continue ;
880                 }
881                 msg2(LOG_INFO,"Authorized client") ;
882                 for(i=0;children[i]&&i<child_arraysize;i++);
883                 if(i>=child_arraysize) {
884                         pid_t*ptr;
885
886                         ptr=realloc(children, sizeof(pid_t)*child_arraysize);
887                         if(ptr) {
888                                 children=ptr;
889                                 memset(children+child_arraysize, 0, sizeof(pid_t)*DEFAULT_CHILD_ARRAY);
890                                 i=child_arraysize+1;
891                                 child_arraysize+=DEFAULT_CHILD_ARRAY;
892                         } else {
893                                 msg2(LOG_INFO,"Not enough memory to store child PID");
894                                 close(net);
895                                 continue;
896                         }
897                 }
898 #ifndef NOFORK
899                 if ((children[i]=fork())<0) {
900                         msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ;
901                         close(net) ;
902                         continue ;
903                 }
904                 if (children[i]>0) { /* parent */
905                         close(net) ; continue ; }
906                 /* child */
907                 realloc(children,0);
908                 child_arraysize=0;
909                 close(sock) ;
910 #endif // NOFORK
911                 msg2(LOG_INFO,"Starting to serve") ;
912                 serveconnection(net) ;        
913         }
914 }
915
916 /**
917  * Main entry point...
918  **/
919 int main(int argc, char *argv[])
920 {
921         if (sizeof( struct nbd_request )!=28) {
922                 fprintf(stderr,"Bad size of structure. Alignment problems?\n");
923                 exit(-1) ;
924         }
925         logging();
926         cmdline(argc, argv);
927         
928         if (!port) return 1 ;
929         connectme(port); /* serve infinitely */
930         return 0 ;
931 }
932