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