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