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