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