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