r78: Make inetd mode actually work (Thanks, Alan Curry)
[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                                 if (i+1<argc) {
314                                         auth_file=argv[++i];
315                                 } else {
316                                         fprintf(stderr, "host list file requires an argument");
317                                 }
318                                 break;
319                         case 'a': 
320                                 if (i+1<argc) {
321                                         timeout = atoi(argv[i+1]);
322                                         i++;
323                                 } else {
324                                         fprintf(stderr, "timeout requires argument\n");
325                                         exit(1);
326                                 }
327                         }
328                 } else {
329                         off_t es;
330                         size_t last = strlen(argv[i])-1;
331                         char suffix = argv[i][last];
332                         if (suffix == 'k' || suffix == 'K' ||
333                             suffix == 'm' || suffix == 'M')
334                                 argv[i][last] = '\0';
335                         es = (off_t)atol(argv[i]);
336                         switch (suffix) {
337                                 case 'm':
338                                 case 'M':  es <<= 10;
339                                 case 'k':
340                                 case 'K':  es <<= 10;
341                                 default :  break;
342                         }
343                         exportsize = es;
344                 }
345         }
346
347         exportname = argv[2];
348 }
349
350 /**
351  * Signal handler for SIGCHLD
352  * @param s the signal we're handling (must be SIGCHLD, or something
353  * is severely wrong)
354  **/
355 void sigchld_handler(int s)
356 {
357         int* status=NULL;
358         int i;
359         char buf[80];
360         pid_t pid;
361
362         while((pid=wait(status)) > 0) {
363                 if(WIFEXITED(status)) {
364                         memset(buf,'\0', 80);
365                         snprintf(buf, 79, "%d", WEXITSTATUS(status));
366                         msg3(LOG_INFO, "Child exited with ", buf);
367                 }
368                 for(i=0;children[i]!=pid&&i<child_arraysize;i++);
369                 if(i>=child_arraysize) {
370                         memset(buf, '\0', 80);
371                         snprintf(buf, 79, "%ld", (long)pid);
372                         msg3(LOG_INFO, "SIGCHLD received for an unknown child with PID ", buf);
373                 } else {
374                         children[i]=(pid_t)0;
375                         DEBUG2("Removing %d from the list of children", pid);
376                 }
377         }
378 }
379
380 /**
381  * Handle SIGTERM and dispatch it to our children
382  * @param s the signal we're handling (must be SIGTERM, or something
383  * is severely wrong).
384  **/
385 void sigterm_handler(int s) {
386         int i;
387         int parent=0;
388
389         for(i=0;i<child_arraysize;i++) {
390                 if(children[i]) {
391                         kill(children[i], s);
392                         parent=1;
393                 }
394         }
395
396         if(parent) {
397                 unlink(pidfname);
398         }
399
400         exit(0);
401 }
402
403 /**
404  * Detect the size of a file.
405  *
406  * @param export An open filedescriptor
407  * @return the size of the file, or OFFT_MAX if detection was
408  * impossible.
409  **/
410 off_t size_autodetect(int export)
411 {
412         off_t es;
413         u32 es32;
414         struct stat stat_buf;
415         int error;
416
417 #ifdef HAVE_SYS_MOUNT_H
418 #ifdef HAVE_SYS_IOCTL_H
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 /* BLKGETSIZE */
426 #endif /* HAVE_SYS_IOCTL_H */
427 #endif /* HAVE_SYS_MOUNT_H */
428
429         DEBUG("looking for export size with fstat\n");
430         stat_buf.st_size = 0;
431         error = fstat(export, &stat_buf);
432         if (!error && stat_buf.st_size > 0) {
433                 return (off_t)stat_buf.st_size;
434         } else {
435                 err("fstat failed: %m");
436         }
437
438         DEBUG("looking for export size with lseek SEEK_END\n");
439         es = lseek(export, (off_t)0, SEEK_END);
440         if (es > ((off_t)0)) {
441                 return es;
442         } else {
443                 DEBUG2("lseek failed: %d", errno==EBADF?1:(errno==ESPIPE?2:(errno==EINVAL?3:4)));
444         }
445
446         err("Could not find size of exported block device: %m");
447         return OFFT_MAX;
448 }
449
450 /**
451  * Seek to a position in a file, unless we're already there.
452  * @param handle a filedescriptor
453  * @param a position to seek to
454  **/
455 void maybeseek(int handle, off_t a) {
456         if (a < 0 || a > exportsize) {
457                 err("Can not happen\n");
458         }
459         if (lastpoint != a) {
460                 if (lseek(handle, a, SEEK_SET) < 0) {
461                         err("Can not seek locally!\n");
462                 }
463                 lastpoint = a;
464         } else {
465                 DEBUG("S");
466         }
467 }
468
469 /**
470  * Write an amount of bytes at a given offset to the right file. This
471  * abstracts the write-side of the multiple file option.
472  *
473  * @param a The offset where the write should start
474  * @param buf The buffer to write from
475  * @param len The length of buf
476  * @return The number of bytes actually written, or -1 in case of an error
477  **/
478 int rawexpwrite(off_t a, char *buf, size_t len)
479 {
480         ssize_t res;
481
482         maybeseek(export[a/hunksize], a%hunksize);
483         res = write(export[a/hunksize], buf, len);
484         return (res < 0 || (size_t)res != len);
485 }
486
487 /**
488  * seek to a position in a file, no matter what. Used when using maybeseek is a
489  * bad idea (for instance, because we're reading the copyonwrite file instead
490  * of the exported file).
491  * @param handle a filedescriptor
492  * @param a position to seek to
493  * @todo get rid of this; lastpoint is a global variable right now, but it
494  * shouldn't be. If we pass it on as a parameter, that makes things a *lot*
495  * easier.
496  **/
497 void myseek(int handle,off_t a) {
498         if (lseek(handle, a, SEEK_SET) < 0) {
499                 err("Can not seek locally!\n");
500         }
501 }
502
503 /**
504  * Read an amount of bytes at a given offset from the right file. This
505  * abstracts the read-side of the multiple files option.
506  *
507  * @param a The offset where the read should start
508  * @param buf A buffer to read into
509  * @param len The size of buf
510  * @return The number of bytes actually read, or -1 in case of an
511  * error.
512  **/
513 int rawexpread(off_t a, char *buf, size_t len)
514 {
515         ssize_t res;
516
517         maybeseek(export[a/hunksize], a%hunksize);
518         res = read(export[a/hunksize], buf, len);
519         return (res < 0 || (size_t)res != len);
520 }
521
522 /**
523  * Read an amount of bytes at a given offset from the right file. This
524  * abstracts the read-side of the copyonwrite stuff, and calls
525  * rawexpread() with the right parameters to do the actual work.
526  * @param a The offset where the read should start
527  * @param buf A buffer to read into
528  * @param len The size of buf
529  * @return The number of bytes actually read, or -1 in case of an error
530  **/
531 int expread(off_t a, char *buf, size_t len)
532 {
533         off_t rdlen, offset;
534         off_t mapcnt, mapl, maph, pagestart;
535  
536         if (!(flags & F_COPYONWRITE))
537                 return rawexpread(a, buf, len);
538         DEBUG3("Asked to read %d bytes at %Lu.\n", len, (unsigned long long)a);
539
540         mapl=a/DIFFPAGESIZE; maph=(a+len-1)/DIFFPAGESIZE;
541
542         for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
543                 pagestart=mapcnt*DIFFPAGESIZE;
544                 offset=a-pagestart;
545                 rdlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
546                         len : (size_t)DIFFPAGESIZE-offset;
547                 if (difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
548                         DEBUG3("Page %Lu is at %lu\n", (unsigned long long)mapcnt,
549                                (unsigned long)difmap[mapcnt]);
550                         myseek(difffile, difmap[mapcnt]*DIFFPAGESIZE+offset);
551                         if (read(difffile, buf, rdlen) != rdlen) return -1;
552                 } else { /* the block is not there */
553                         DEBUG2("Page %Lu is not here, we read the original one\n",
554                                (unsigned long long)mapcnt);
555                         return rawexpread(a, buf, rdlen);
556                 }
557                 len-=rdlen; a+=rdlen; buf+=rdlen;
558         }
559         return 0;
560 }
561
562 /**
563  * Write an amount of bytes at a given offset to the right file. This
564  * abstracts the write-side of the copyonwrite option, and calls
565  * rawexpwrite() with the right parameters to do the actual work.
566  *
567  * @param a The offset where the write should start
568  * @param buf The buffer to write from
569  * @param len The length of buf
570  * @return The number of bytes actually written, or -1 in case of an error
571  **/
572 int expwrite(off_t a, char *buf, size_t len)
573 {
574         off_t mapcnt,mapl,maph ;
575         off_t wrlen,rdlen ; 
576         off_t pagestart ;
577         off_t offset ;
578
579         if (!(flags & F_COPYONWRITE))
580                 return(rawexpwrite(a,buf,len)); 
581         DEBUG3("Asked to write %d bytes at %Lu.\n", len, (unsigned long long)a);
582
583         mapl=a/DIFFPAGESIZE ; maph=(a+len-1)/DIFFPAGESIZE ;
584
585         for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
586                 pagestart=mapcnt*DIFFPAGESIZE ;
587                 offset=a-pagestart ;
588                 wrlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
589                         len : (size_t)DIFFPAGESIZE-offset;
590
591                 if (difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
592                         DEBUG3("Page %Lu is at %lu\n", (unsigned long long)mapcnt,
593                                (unsigned long)difmap[mapcnt]) ;
594                         myseek(difffile,difmap[mapcnt]*DIFFPAGESIZE+offset) ;
595                         if (write(difffile, buf, wrlen) != wrlen) return -1 ;
596                 } else { /* the block is not there */
597                         myseek(difffile,difffilelen*DIFFPAGESIZE) ;
598                         difmap[mapcnt]=difffilelen++ ;
599                         DEBUG3("Page %Lu is not here, we put it at %lu\n",
600                                (unsigned long long)mapcnt,
601                                (unsigned long)difmap[mapcnt]);
602                         rdlen=DIFFPAGESIZE ;
603                         if (rdlen+pagestart%hunksize>hunksize) 
604                                 rdlen=hunksize-(pagestart%hunksize) ;
605                         if (rawexpread(pagestart,pagebuf,rdlen)) return -1 ;
606                         memcpy(pagebuf+offset,buf,wrlen) ;
607                         if (write(difffile,pagebuf,DIFFPAGESIZE)!=DIFFPAGESIZE) return -1 ;
608                 }                                                   
609                 len-=wrlen ; a+=wrlen ; buf+=wrlen ;
610         }
611         return 0;
612 }
613
614 /**
615  * Do the initial negotiation.
616  *
617  * @param net A socket to do the negotiation over
618  **/
619 void negotiate(int net) {
620         char zeros[300];
621         u64 size_host;
622
623         memset(zeros, 0, 290);
624         if (write(net, INIT_PASSWD, 8) < 0)
625                 err("Negotiation failed: %m");
626         cliserv_magic = htonll(cliserv_magic);
627         if (write(net, &cliserv_magic, sizeof(cliserv_magic)) < 0)
628                 err("Negotiation failed: %m");
629         size_host = htonll((u64)exportsize);
630         if (write(net, &size_host, 8) < 0)
631                 err("Negotiation failed: %m");
632         if (write(net, zeros, 128) < 0)
633                 err("Negotiation failed: %m");
634 }
635
636 /** sending macro; not really required. Uses variables in the local
637  * scope of mainloop(). Get rid of it. */
638 #define SEND writeit( net, &reply, sizeof( reply ));
639 /** error macro; not sure whether we really need this. Uses variables
640  * in the local scope of mainloop(). Get rid of this beast. */
641 #define ERROR { reply.error = htonl(-1); SEND; reply.error = 0; lastpoint = -1; }
642 /**
643  * Serve a file to a single client.
644  *
645  * @todo This beast needs to be split up in many tiny little manageable
646  * pieces. Preferably with a chainsaw.
647  *
648  * @param net A network socket, connected to an nbd client
649  * @return never
650  **/
651 int mainloop(int net)
652 {
653         struct nbd_request request;
654         struct nbd_reply reply;
655 #ifdef DODBG
656         int i = 0;
657 #endif
658         negotiate(net);
659         DEBUG("Entering request loop!\n");
660         reply.magic = htonl(NBD_REPLY_MAGIC);
661         reply.error = 0;
662         while (1) {
663                 char buf[BUFSIZE];
664                 size_t len;
665 #ifdef DODBG
666                 i++;
667                 printf("%d: ", i);
668 #endif
669                 if (timeout) 
670                         alarm(timeout);
671                 readit(net, &request, sizeof(request));
672                 request.from = ntohll(request.from);
673                 request.type = ntohl(request.type);
674
675                 if (request.type==NBD_CMD_DISC) { /* Disconnect request */
676                   if (difmap) free(difmap) ;
677                   if (difffile>=0) { 
678                      close(difffile) ; unlink(difffilename) ; }
679                   err("Disconnect request received.") ;
680                 }
681
682                 len = ntohl(request.len);
683
684                 if (request.magic != htonl(NBD_REQUEST_MAGIC))
685                         err("Not enough magic.");
686                 if (len > BUFSIZE)
687                         err("Request too big!");
688 #ifdef DODBG
689                 printf("%s from %Lu (%Lu) len %d, ", request.type ? "WRITE" :
690                                 "READ", (unsigned long long)request.from,
691                                 (unsigned long long)request.from / 512, len);
692 #endif
693                 memcpy(reply.handle, request.handle, sizeof(reply.handle));
694                 if ((request.from + len) > (OFFT_MAX)) {
695                   DEBUG("[Number too large!]");
696                   ERROR;
697                   continue;
698                 }
699
700                 if (((ssize_t)((off_t)request.from + len) > exportsize) ||
701                     ((flags & F_READONLY) && request.type)) {
702                         DEBUG("[RANGE!]");
703                         ERROR;
704                         continue;
705                 }
706
707                 if (request.type==1) {  /* WRITE */
708                         DEBUG("wr: net->buf, ");
709                         readit(net, buf, len);
710                         DEBUG("buf->exp, ");
711                         if ((autoreadonly == 1) || expwrite(request.from, buf, len)) {
712                                 DEBUG("Write failed: %m" );
713                                 ERROR;
714                                 continue;
715                         }
716                         lastpoint += len;
717                         SEND;
718                         DEBUG("OK!\n");
719                         continue;
720                 }
721                 /* READ */
722
723                 DEBUG("exp->buf, ");
724                 if (expread(request.from, buf + sizeof(struct nbd_reply), len)) {
725                         lastpoint = -1;
726                         DEBUG("Read failed: %m");
727                         ERROR;
728                         continue;
729                 }
730                 lastpoint += len;
731
732                 DEBUG("buf->net, ");
733                 memcpy(buf, &reply, sizeof(struct nbd_reply));
734                 writeit(net, buf, len + sizeof(struct nbd_reply));
735                 DEBUG("OK!\n");
736         }
737 }
738
739 /**
740  * Split a single exportfile into multiple ones, if that was asked.
741  * @return 0 on success, -1 on failure
742  **/
743 int splitexport(void) {
744         off_t i ;
745
746         for (i=0; i<exportsize; i+=hunksize) {
747                 char exportname3[1024];
748
749                 if(flags & F_MULTIFILE) {
750                         snprintf(exportname3, 1024, "%s.%d", exportname2, (int)(i/hunksize));
751                 } else {
752                         strncpy(exportname3, exportname2, 1024);
753                 }
754                 exportname3[1023]='\0';
755                 DEBUG2( "Opening %s\n", exportname3 );
756                 if ((export[i/hunksize] = open(exportname3, (flags & F_READONLY) ? O_RDONLY : O_RDWR)) == -1) {
757                         /* Read WRITE ACCESS was requested by media is only read only */
758                         autoreadonly = 1;
759                         flags |= F_READONLY;
760                         if ((export[i/hunksize] = open(exportname3, O_RDONLY)) == -1) 
761                                 err("Could not open exported file: %m");
762                 }
763         }
764
765         if (flags & F_COPYONWRITE) {
766                 snprintf(difffilename, 1024, "%s-%s-%d.diff",exportname2,clientname,
767                         (int)getpid()) ;
768                 difffilename[1023]='\0';
769                 msg3(LOG_INFO,"About to create map and diff file %s",difffilename) ;
770                 difffile=open(difffilename,O_RDWR | O_CREAT | O_TRUNC,0600) ;
771                 if (difffile<0) err("Could not create diff file (%m)") ;
772                 if ((difmap=calloc(exportsize/DIFFPAGESIZE,sizeof(u32)))==NULL)
773                         err("Could not allocate memory") ;
774                 for (i=0;i<exportsize/DIFFPAGESIZE;i++) difmap[i]=(u32)-1 ;
775         }
776
777         return 0;
778 }
779
780 /**
781  * Serve a connection. 
782  *
783  * @todo allow for multithreading, perhaps use libevent.
784  *
785  * @param net A network socket connected to an nbd client
786  **/
787 void serveconnection(int net) {
788         char buf[80];
789         splitexport();
790         if (exportsize == OFFT_MAX) {
791                 exportsize = size_autodetect(export[0]);
792         }
793         if (exportsize > OFFT_MAX) {
794                 err("Size of exported file is too big\n");
795         }
796         else {
797                 memset(buf, '\0', 80);
798                 snprintf(buf, 79, "%Lu", (unsigned long long)exportsize);
799                 msg3(LOG_INFO, "size of exported file/device is ", buf);
800         }
801
802         setmysockopt(net);
803
804         mainloop(net);
805 }
806
807 /**
808  * Find the name of the file we have to serve. This will use snprintf()
809  * to put the IP address of the client inside a filename containing
810  * "%s". That name is then written to exportname2
811  *
812  * @param net A socket connected to an nbd client
813  * @param clientname a buffer which must be at least 255+1 bytes long;
814  * the IP address (in human-readable format) will be copied in there.
815  **/
816 void set_peername(int net,char *clientname)
817 {
818         struct sockaddr_in addrin;
819         int addrinlen = sizeof( addrin );
820         char *peername ;
821
822         if (getpeername( net, (struct sockaddr *) &addrin, &addrinlen ) < 0)
823                 err("getsockname failed: %m");
824         peername = inet_ntoa(addrin.sin_addr);
825         snprintf(exportname2, 1024, exportname, peername);
826         exportname2[1023]='\0';
827
828         msg4(LOG_INFO, "connect from %s, assigned file is %s", 
829              peername, exportname2);
830         strncpy(clientname,peername,255) ;
831 }
832
833 /**
834  * Connect the socket, and start to serve. This function will fork()
835  * if a connection from an authorized client is received, and will
836  * start mainloop().
837  *
838  * @todo modularize this giant beast. Preferably with a chainsaw. Also,
839  * it has no business starting mainloop(); it should connect, and be
840  * done with it.
841  *
842  * @param port the port where we will listen
843  **/
844 void connectme(unsigned int port)
845 {
846         struct sockaddr_in addrin;
847         struct sigaction sa;
848         int addrinlen = sizeof(addrin);
849         int net, sock, newpid, i;
850 #ifndef sun
851         int yes=1;
852 #else
853         char yes='1';
854 #endif /* sun */
855 #ifndef NODAEMON
856 #ifndef NOFORK
857         FILE*pidf;
858
859         if(port) {
860                 if(daemon(0,0)<0) {
861                         err("daemon");
862                 }
863                 snprintf(pidfname, sizeof(char)*255, "/var/run/nbd-server.%d.pid", port);
864                 pidf=fopen(pidfname, "w");
865                 if(pidf) {
866                         fprintf(pidf,"%d", (int)getpid());
867                         fclose(pidf);
868                 } else {
869                         perror("fopen");
870                         fprintf(stderr, "Not fatal; continuing");
871                 }
872         }
873 #endif /* NOFORK */
874 #endif /* NODAEMON */
875
876         if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
877                 err("socket: %m");
878
879         /* lose the pesky "Address already in use" error message */
880         if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
881                 err("setsockopt SO_REUSEADDR");
882         }
883         if (setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,&yes,sizeof(int)) == -1) {
884                 err("setsockopt SO_KEEPALIVE");
885         }
886
887         DEBUG("Waiting for connections... bind, ");
888         addrin.sin_family = AF_INET;
889         addrin.sin_port = htons(port);
890         addrin.sin_addr.s_addr = 0;
891         if (bind(sock, (struct sockaddr *) &addrin, addrinlen) < 0)
892                 err("bind: %m");
893         DEBUG("listen, ");
894         if (listen(sock, 1) < 0)
895                 err("listen: %m");
896         DEBUG("accept, ");
897         sa.sa_handler = sigchld_handler;
898         sigemptyset(&sa.sa_mask);
899         sa.sa_flags = SA_RESTART;
900         if(sigaction(SIGCHLD, &sa, NULL) == -1)
901                 err("sigaction: %m");
902         sa.sa_handler = sigterm_handler;
903         sigemptyset(&sa.sa_mask);
904         sa.sa_flags = SA_RESTART;
905         if(sigaction(SIGTERM, &sa, NULL) == -1)
906                 err("sigaction: %m");
907         children=malloc(sizeof(pid_t)*child_arraysize);
908         memset(children, 0, sizeof(pid_t)*DEFAULT_CHILD_ARRAY);
909         for(;;) { /* infinite loop */
910                 if ((net = accept(sock, (struct sockaddr *) &addrin, &addrinlen)) < 0)
911                         err("accept: %m");
912                 
913                 set_peername(net,clientname);
914                 if (!authorized_client(clientname)) {
915                         msg2(LOG_INFO,"Unauthorized client") ;
916                         close(net) ;
917                         continue ;
918                 }
919                 msg2(LOG_INFO,"Authorized client") ;
920                 for(i=0;children[i]&&i<child_arraysize;i++);
921                 if(i>=child_arraysize) {
922                         pid_t*ptr;
923
924                         ptr=realloc(children, sizeof(pid_t)*child_arraysize);
925                         if(ptr) {
926                                 children=ptr;
927                                 memset(children+child_arraysize, 0, sizeof(pid_t)*DEFAULT_CHILD_ARRAY);
928                                 i=child_arraysize+1;
929                                 child_arraysize+=DEFAULT_CHILD_ARRAY;
930                         } else {
931                                 msg2(LOG_INFO,"Not enough memory to store child PID");
932                                 close(net);
933                                 continue;
934                         }
935                 }
936 #ifndef NOFORK
937                 if ((children[i]=fork())<0) {
938                         msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ;
939                         close(net) ;
940                         continue ;
941                 }
942                 if (children[i]>0) { /* parent */
943                         close(net) ; continue ; }
944                 /* child */
945                 realloc(children,0);
946                 child_arraysize=0;
947                 close(sock) ;
948 #endif // NOFORK
949                 msg2(LOG_INFO,"Starting to serve") ;
950                 serveconnection(net) ;        
951         }
952 }
953
954 /**
955  * Main entry point...
956  **/
957 int main(int argc, char *argv[])
958 {
959         if (sizeof( struct nbd_request )!=28) {
960                 fprintf(stderr,"Bad size of structure. Alignment problems?\n");
961                 exit(-1) ;
962         }
963         logging();
964         cmdline(argc, argv);
965         
966         if (!port) {
967 #ifndef ISSERVER
968           /* You really should define ISSERVER if you're going to use inetd
969            * mode, but if you don't, closing stdout and stderr (which inetd
970            * had connected to the client socket) will let it work. */
971           close(1);
972           close(2);
973           open("/dev/null", O_WRONLY);
974           open("/dev/null", O_WRONLY);
975 #endif
976           set_peername(0,clientname);
977           serveconnection(0);
978           return 0;
979         }
980         connectme(port); /* serve infinitely */
981         return 0 ;
982 }
983