r165: Remove outdated comments
[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 /** Default position of the config file */
92 #ifndef SYSCONFDIR
93 #define SYSCONFDIR "/etc"
94 #endif
95 #define CFILE SYSCONFDIR "/nbd-server/config"
96
97 /** Where our config file actually is */
98 gchar* config_file_pos;
99
100 /** how much space for child PIDs we have by default. Dynamically
101    allocated, and will be realloc()ed if out of space, so this should
102    probably be fair for most situations. */
103 #define DEFAULT_CHILD_ARRAY 256
104
105 /** Logging macros, now nothing goes to syslog unless you say ISSERVER */
106 #ifdef ISSERVER
107 #define msg2(a,b) syslog(a,b)
108 #define msg3(a,b,c) syslog(a,b,c)
109 #define msg4(a,b,c,d) syslog(a,b,c,d)
110 #else
111 #define msg2(a,b) g_message(b)
112 #define msg3(a,b,c) g_message(b,c)
113 #define msg4(a,b,c,d) g_message(b,c,d)
114 #endif
115
116 /* Debugging macros */
117 //#define DODBG
118 #ifdef DODBG
119 #define DEBUG( a ) printf( a )
120 #define DEBUG2( a,b ) printf( a,b )
121 #define DEBUG3( a,b,c ) printf( a,b,c )
122 #else
123 #define DEBUG( a )
124 #define DEBUG2( a,b ) 
125 #define DEBUG3( a,b,c ) 
126 #endif
127 #ifndef PACKAGE_VERSION
128 #define PACKAGE_VERSION ""
129 #endif
130 /**
131  * The highest value a variable of type off_t can reach.
132  **/
133 /* This is starting to get ugly. If someone knows a better way to find
134  * the maximum value of a signed type *without* relying on overflow
135  * (doing so breaks on 64bit architectures), that would be nice.
136  *
137  * Actually, do we need this at all? Can't we just say '0 is autodetect', and
138  * live with it? Or better yet, use an extra flag, or so?
139  * Answer: yes, we need it, as the hunksize is defined to this when the
140  * multiple file thingy isn't used.
141  */
142 #define OFFT_MAX (((((off_t)1)<<((sizeof(off_t)-1)*8))-1)<<7)+127
143 #define LINELEN 256       /**< Size of static buffer used to read the
144                             authorization file (yuck) */
145 #define BUFSIZE (1024*1024) /**< Size of buffer that can hold requests */
146 #define GIGA (1*1024*1024*1024) /**< 1 Gigabyte. Used as hunksize when doing
147                                   the multiple file thingy. @todo: make this a
148                                   configuration option. */
149 #define DIFFPAGESIZE 4096 /**< diff file uses those chunks */
150 #define F_READONLY 1      /**< flag to tell us a file is readonly */
151 #define F_MULTIFILE 2     /**< flag to tell us a file is exported using -m */
152 #define F_COPYONWRITE 4   /**< flag to tell us a file is exported using
153                             copyonwrite */
154 #define F_AUTOREADONLY 8  /**< flag to tell us a file is set to autoreadonly */
155 GHashTable *children;
156 char pidfname[256]; /**< name of our PID file */
157 char default_authname[] = "/etc/nbd_server.allow"; /**< default name of allow file */
158
159 /**
160  * Variables associated with a server.
161  **/
162 typedef struct {
163         gchar* exportname;    /**< (unprocessed) filename of the file we're exporting */
164         off_t hunksize;      /**< size of a hunk of an exported file */
165         off_t expected_size; /**< size of the exported file as it was told to
166                                us through configuration */
167         unsigned int port;   /**< port we're exporting this file at */
168         char* authname;      /**< filename of the authorization file */
169         int flags;           /**< flags associated with this exported file */
170         unsigned int timeout;/**< how long a connection may be idle
171                                (0=forever) */
172         int socket;          /**< The socket of this server. */
173 } SERVER;
174
175 /**
176  * Variables associated with a client socket.
177  **/
178 typedef struct {
179         off_t exportsize;    /**< size of the file we're exporting */
180         char *clientname;    /**< peer */
181         char *exportname;    /**< (processed) filename of the file we're exporting */
182         GArray *export;    /**< array of filedescriptors of exported files;
183                                only the first is actually used unless we're
184                                doing the multiple file option */
185         int net;             /**< The actual client socket */
186         SERVER *server;      /**< The server this client is getting data from */
187         char* difffilename;  /**< filename of the copy-on-write file, if any */
188         int difffile;        /**< filedescriptor of copyonwrite file. @todo
189                                shouldn't this be an array too? (cfr export) Or
190                                make -m and -c mutually exclusive */
191         u32 difffilelen;     /**< number of pages in difffile */
192         u32 *difmap;         /**< see comment on the global difmap for this one */
193 } CLIENT;
194
195 /**
196  * Type of configuration file values
197  **/
198 typedef enum {
199         PARAM_INT,              /**< This parameter is an integer */
200         PARAM_STRING,           /**< This parameter is a string */
201         PARAM_BOOL,             /**< This parameter is a boolean */
202 } PARAM_TYPE;
203 /**
204  * Configuration file values
205  **/
206 typedef struct {
207         gchar *paramname;       /**< Name of the parameter, as it appears in
208                                   the config file */
209         gboolean required;      /**< Whether this is a required (as opposed to
210                                   optional) parameter */
211         PARAM_TYPE ptype;       /**< Type of the parameter. */
212         gpointer target;        /**< Pointer to where the data of this
213                                   parameter should be written. If ptype is
214                                   PARAM_BOOL, the data is or'ed rather than
215                                   overwritten. */
216         gint flagval;           /**< Flag mask for this parameter in case ptype
217                                   is PARAM_BOOL. */
218 } PARAM;
219
220 /**
221  * Check whether a client is allowed to connect. Works with an authorization
222  * file which contains one line per machine, no wildcards.
223  *
224  * @param opts The client who's trying to connect.
225  * @return 0 - authorization refused, 1 - OK
226  **/
227 int authorized_client(CLIENT *opts) {
228         FILE *f ;
229    
230         char line[LINELEN]; 
231
232         if ((f=fopen(opts->server->authname,"r"))==NULL) {
233                 msg4(LOG_INFO,"Can't open authorization file %s (%s).",
234                      opts->server->authname,strerror(errno)) ;
235                 return 1 ; 
236         }
237   
238         while (fgets(line,LINELEN,f)!=NULL) {
239                 if (strncmp(line,opts->clientname,strlen(opts->clientname))==0) {
240                         fclose(f);
241                         return 1;
242                 }
243         }
244         fclose(f) ;
245         return 0 ;
246 }
247
248 /**
249  * Read data from a file descriptor into a buffer
250  *
251  * @param f a file descriptor
252  * @param buf a buffer
253  * @param len the number of bytes to be read
254  **/
255 inline void readit(int f, void *buf, size_t len) {
256         ssize_t res;
257         while (len > 0) {
258                 DEBUG("*");
259                 if ((res = read(f, buf, len)) <= 0)
260                         err("Read failed: %m");
261                 len -= res;
262                 buf += res;
263         }
264 }
265
266 /**
267  * Write data from a buffer into a filedescriptor
268  *
269  * @param f a file descriptor
270  * @param buf a buffer containing data
271  * @param len the number of bytes to be written
272  **/
273 inline void writeit(int f, void *buf, size_t len) {
274         ssize_t res;
275         while (len > 0) {
276                 DEBUG("+");
277                 if ((res = write(f, buf, len)) <= 0)
278                         err("Send failed: %m");
279                 len -= res;
280                 buf += res;
281         }
282 }
283
284 /**
285  * Print out a message about how to use nbd-server. Split out to a separate
286  * function so that we can call it from multiple places
287  */
288 void usage() {
289         printf("This is nbd-server version " VERSION "\n");
290         printf("Usage: port file_to_export [size][kKmM] [-l authorize_file] [-r] [-m] [-c] [-a timeout_sec] [-C configuration file]\n"
291                "\t-r|--read-only\t\tread only\n"
292                "\t-m|--multi-file\t\tmultiple file\n"
293                "\t-c|--copy-on-write\tcopy on write\n"
294                "\t-C|--config-file\tspecify an alternat configuration file\n"
295                "\t-l|--authorize-file\tfile with list of hosts that are allowed to\n\t\t\t\tconnect.\n"
296                "\t-a|--idle-time\t\tmaximum idle seconds; server terminates when\n\t\t\t\tidle time exceeded\n\n"
297                "\tif port is set to 0, stdin is used (for running from inetd)\n"
298                "\tif file_to_export contains '%%s', it is substituted with the IP\n"
299                "\t\taddress of the machine trying to connect\n" );
300         printf("Using configuration file %s\n", CFILE);
301 }
302
303 /**
304  * Parse the command line.
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=0;
311         int nonspecial=0;
312         int c;
313         struct option long_options[] = {
314                 {"read-only", no_argument, NULL, 'r'},
315                 {"multi-file", no_argument, NULL, 'm'},
316                 {"copy-on-write", no_argument, NULL, 'c'},
317                 {"authorize-file", required_argument, NULL, 'l'},
318                 {"idle-time", required_argument, NULL, 'a'},
319                 {"config-file", required_argument, NULL, 'C'},
320                 {0,0,0,0}
321         };
322         SERVER *serve;
323         off_t es;
324         size_t last;
325         char suffix;
326
327         if(argc==1) {
328                 return NULL;
329         }
330         serve=g_new0(SERVER, 1);
331         serve->hunksize=OFFT_MAX;
332         serve->authname = g_strdup(default_authname);
333         while((c=getopt_long(argc, argv, "-a:C:cl:mr", long_options, &i))>=0) {
334                 switch (c) {
335                 case 1:
336                         /* non-option argument */
337                         switch(nonspecial++) {
338                         case 0:
339                                 serve->port=strtol(optarg, NULL, 0);
340                                 break;
341                         case 1:
342                                 serve->exportname = g_strdup(optarg);
343                                 if(serve->exportname[0] != '/') {
344                                         fprintf(stderr, "E: The to be exported file needs to be an absolute filename!\n");
345                                         exit(EXIT_FAILURE);
346                                 }
347                                 break;
348                         case 2:
349                                 last=strlen(optarg)-1;
350                                 suffix=optarg[last];
351                                 if (suffix == 'k' || suffix == 'K' ||
352                                     suffix == 'm' || suffix == 'M')
353                                         optarg[last] = '\0';
354                                 es = (off_t)atol(optarg);
355                                 switch (suffix) {
356                                         case 'm':
357                                         case 'M':  es <<= 10;
358                                         case 'k':
359                                         case 'K':  es <<= 10;
360                                         default :  break;
361                                 }
362                                 serve->expected_size = es;
363                                 break;
364                         }
365                         break;
366                 case 'r':
367                         serve->flags |= F_READONLY;
368                         break;
369                 case 'm':
370                         serve->flags |= F_MULTIFILE;
371                         serve->hunksize = 1*GIGA;
372                         break;
373                 case 'c': 
374                         serve->flags |=F_COPYONWRITE;
375                         break;
376                 case 'C':
377                         g_free(config_file_pos);
378                         config_file_pos=g_strdup(optarg);
379                         break;
380                 case 'l':
381                         g_free(serve->authname);
382                         serve->authname=g_strdup(optarg);
383                         break;
384                 case 'a': 
385                         serve->timeout=strtol(optarg, NULL, 0);
386                         break;
387                 default:
388                         usage();
389                         exit(EXIT_FAILURE);
390                         break;
391                 }
392         }
393         /* What's left: the port to export, the name of the to be exported
394          * file, and, optionally, the size of the file, in that order. */
395         if(nonspecial<2) {
396                 g_free(serve);
397                 serve=NULL;
398         }
399         return serve;
400 }
401
402 /**
403  * Error codes for config file parsing
404  **/
405 typedef enum {
406         CFILE_NOTFOUND,         /**< The configuration file is not found */
407         CFILE_MISSING_GENERIC,  /**< The (required) group "generic" is missing */
408         CFILE_KEY_MISSING,      /**< A (required) key is missing */
409         CFILE_VALUE_INVALID,    /**< A value is syntactically invalid */
410         CFILE_PROGERR           /**< Programmer error */
411 } CFILE_ERRORS;
412
413 /**
414  * Remove a SERVER from memory. Used from the hash table
415  **/
416 void remove_server(gpointer s) {
417         SERVER *server;
418
419         server=(SERVER*)s;
420         g_free(server->exportname);
421         if(server->authname)
422                 g_free(server->authname);
423         g_free(server);
424 }
425
426 /**
427  * Parse the config file.
428  *
429  * @param f the name of the config file
430  * @param e a GError. @see CFILE_ERRORS for what error values this function can
431  *      return.
432  * @return a GHashTable of SERVER* pointers, with the port number as the hash
433  *      key. If the config file is empty or does not exist, returns an empty
434  *      GHashTable; if the config file contains an error, returns NULL, and
435  *      e is set appropriately
436  **/
437 GArray* parse_cfile(gchar* f, GError** e) {
438         SERVER s;
439         PARAM p[] = {
440                 { "exportname", TRUE,   PARAM_STRING,   NULL, 0 },
441                 { "port",       TRUE,   PARAM_INT,      NULL, 0 },
442                 { "authfile",   FALSE,  PARAM_STRING,   NULL, 0 },
443                 { "timeout",    FALSE,  PARAM_INT,      NULL, 0 },
444                 { "filesize",   FALSE,  PARAM_INT,      NULL, 0 },
445                 { "readonly",   FALSE,  PARAM_BOOL,     NULL, F_READONLY },
446                 { "multifile",  FALSE,  PARAM_BOOL,     NULL, F_MULTIFILE },
447                 { "copyonwrite", FALSE, PARAM_BOOL,     NULL, F_COPYONWRITE },
448         };
449         const int p_size=8;
450         GKeyFile *cfile;
451         GError *err = NULL;
452         GQuark errdomain;
453         GArray *retval=NULL;
454         gchar **groups;
455         gboolean value;
456         gint i,j;
457
458         memset(&s, '\0', sizeof(SERVER));
459         errdomain = g_quark_from_string("parse_cfile");
460         cfile = g_key_file_new();
461         retval = g_array_new(FALSE, TRUE, sizeof(SERVER));
462         if(!g_key_file_load_from_file(cfile, f, G_KEY_FILE_KEEP_COMMENTS |
463                         G_KEY_FILE_KEEP_TRANSLATIONS, &err)) {
464                 g_set_error(e, errdomain, CFILE_NOTFOUND, "Could not open config file.");
465                 g_key_file_free(cfile);
466                 return retval;
467         }
468         if(strcmp(g_key_file_get_start_group(cfile), "generic")) {
469                 g_set_error(e, errdomain, CFILE_MISSING_GENERIC, "Config file does not contain the [generic] group!");
470                 g_key_file_free(cfile);
471                 return NULL;
472         }
473         groups = g_key_file_get_groups(cfile, NULL);
474         for(i=1;groups[i];i++) {
475                 p[0].target=&(s.exportname);
476                 p[1].target=&(s.port);
477                 p[2].target=&(s.authname);
478                 p[3].target=&(s.timeout);
479                 p[4].target=&(s.expected_size);
480                 p[5].target=p[6].target=p[7].target=p[8].target=&(s.flags);
481                 for(j=0;j<p_size;j++) {
482                         g_assert(p[j].target != NULL);
483                         g_assert(p[j].ptype==PARAM_INT||p[j].ptype==PARAM_STRING||p[j].ptype==PARAM_BOOL);
484                         switch(p[j].ptype) {
485                                 case PARAM_INT:
486                                         *((gint*)p[j].target) =
487                                                 g_key_file_get_integer(cfile,
488                                                                 groups[i],
489                                                                 p[j].paramname,
490                                                                 &err);
491                                         break;
492                                 case PARAM_STRING:
493                                         *((gchar**)p[j].target) =
494                                                 g_key_file_get_string(cfile,
495                                                                 groups[i],
496                                                                 p[j].paramname,
497                                                                 &err);
498                                         break;
499                                 case PARAM_BOOL:
500                                         value = g_key_file_get_boolean(cfile,
501                                                         groups[i],
502                                                         p[j].paramname, &err);
503                                         if(!err) {
504                                                 *((gint*)p[j].target) |= value;
505                                         }
506                                         break;
507                         }
508                         if(err) {
509                                 if(err->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
510                                         if(p[j].required) {
511                                                 g_set_error(e, errdomain, CFILE_KEY_MISSING, "Could not find required value %s in group %s: %s", p[j].paramname, groups[i], err->message);
512                                                 g_array_free(retval, TRUE);
513                                                 g_error_free(err);
514                                                 g_key_file_free(cfile);
515                                                 return NULL;
516                                         } else {
517                                                 g_clear_error(&err);
518                                                 continue;
519                                         }
520                                         g_set_error(e, errdomain, CFILE_VALUE_INVALID, "Could not parse %s in group %s: %s", p[j].paramname, groups[i], err->message);
521                                         g_array_free(retval, TRUE);
522                                         g_error_free(err);
523                                         g_key_file_free(cfile);
524                                         return NULL;
525                                 }
526                         }
527                 }
528                 g_array_append_val(retval, s);
529         }
530         return retval;
531 }
532
533 /**
534  * Signal handler for SIGCHLD
535  * @param s the signal we're handling (must be SIGCHLD, or something
536  * is severely wrong)
537  **/
538 void sigchld_handler(int s) {
539         int* status=NULL;
540         int* i;
541         pid_t pid;
542
543         while((pid=wait(status)) > 0) {
544                 if(WIFEXITED(status)) {
545                         msg3(LOG_INFO, "Child exited with %d", WEXITSTATUS(status));
546                 }
547                 i=g_hash_table_lookup(children, &pid);
548                 if(!i) {
549                         msg3(LOG_INFO, "SIGCHLD received for an unknown child with PID %ld", (long)pid);
550                 } else {
551                         DEBUG2("Removing %d from the list of children", pid);
552                         g_hash_table_remove(children, &pid);
553                 }
554         }
555 }
556
557 /**
558  * Kill a child. Called from sigterm_handler::g_hash_table_foreach.
559  *
560  * @param key the key
561  * @param value the value corresponding to the above key
562  * @param user_data a pointer which we always set to 1, so that we know what
563  * will happen next.
564  **/
565 void killchild(gpointer key, gpointer value, gpointer user_data) {
566         pid_t *pid=value;
567         int *parent=user_data;
568
569         kill(*pid, SIGTERM);
570         *parent=1;
571 }
572
573 /**
574  * Handle SIGTERM and dispatch it to our children
575  * @param s the signal we're handling (must be SIGTERM, or something
576  * is severely wrong).
577  **/
578 void sigterm_handler(int s) {
579         int parent=0;
580
581         g_hash_table_foreach(children, killchild, &parent);
582
583         if(parent) {
584                 unlink(pidfname);
585         }
586
587         exit(0);
588 }
589
590 /**
591  * Detect the size of a file.
592  *
593  * @param export An open filedescriptor
594  * @return the size of the file, or OFFT_MAX if detection was
595  * impossible.
596  **/
597 off_t size_autodetect(int export) {
598         off_t es;
599         u32 es32;
600         struct stat stat_buf;
601         int error;
602
603 #ifdef HAVE_SYS_MOUNT_H
604 #ifdef HAVE_SYS_IOCTL_H
605 #ifdef BLKGETSIZE
606         DEBUG("looking for export size with ioctl BLKGETSIZE\n");
607         if (!ioctl(export, BLKGETSIZE, &es32) && es32) {
608                 es = (off_t)es32 * (off_t)512;
609                 return es;
610         }
611 #endif /* BLKGETSIZE */
612 #endif /* HAVE_SYS_IOCTL_H */
613 #endif /* HAVE_SYS_MOUNT_H */
614
615         DEBUG("looking for export size with fstat\n");
616         stat_buf.st_size = 0;
617         error = fstat(export, &stat_buf);
618         if (!error) {
619                 if(stat_buf.st_size > 0)
620                         return (off_t)stat_buf.st_size;
621         } else {
622                 err("fstat failed: %m");
623         }
624
625         DEBUG("looking for export size with lseek SEEK_END\n");
626         es = lseek(export, (off_t)0, SEEK_END);
627         if (es > ((off_t)0)) {
628                 return es;
629         } else {
630                 DEBUG2("lseek failed: %d", errno==EBADF?1:(errno==ESPIPE?2:(errno==EINVAL?3:4)));
631         }
632
633         err("Could not find size of exported block device: %m");
634         return OFFT_MAX;
635 }
636
637 /**
638  * seek to a position in a file, with error handling.
639  * @param handle a filedescriptor
640  * @param a position to seek to
641  * @todo get rid of this; lastpoint is a global variable right now, but it
642  * shouldn't be. If we pass it on as a parameter, that makes things a *lot*
643  * easier.
644  **/
645 void myseek(int handle,off_t a) {
646         if (lseek(handle, a, SEEK_SET) < 0) {
647                 err("Can not seek locally!\n");
648         }
649 }
650
651 /**
652  * Write an amount of bytes at a given offset to the right file. This
653  * abstracts the write-side of the multiple file option.
654  *
655  * @param a The offset where the write should start
656  * @param buf The buffer to write from
657  * @param len The length of buf
658  * @param client The client we're serving for
659  * @return The number of bytes actually written, or -1 in case of an error
660  **/
661 int rawexpwrite(off_t a, char *buf, size_t len, CLIENT *client) {
662         ssize_t res;
663
664         myseek(g_array_index(client->export, int, (int)(a/client->server->hunksize)), a%client->server->hunksize);
665         ;
666         res = write(g_array_index(client->export, int, (int)((off_t)a/(off_t)(client->server->hunksize))), buf, len);
667         return (res < 0 || (size_t)res != len);
668 }
669
670 /**
671  * Read an amount of bytes at a given offset from the right file. This
672  * abstracts the read-side of the multiple files option.
673  *
674  * @param a The offset where the read should start
675  * @param buf A buffer to read into
676  * @param len The size of buf
677  * @param client The client we're serving for
678  * @return The number of bytes actually read, or -1 in case of an
679  * error.
680  **/
681 int rawexpread(off_t a, char *buf, size_t len, CLIENT *client) {
682         ssize_t res;
683
684         myseek(g_array_index(client->export,int,(int)a/client->server->hunksize),
685                         a%client->server->hunksize);
686         res = read(g_array_index(client->export,int,(int)a/client->server->hunksize), buf, len);
687         return (res < 0 || (size_t)res != len);
688 }
689
690 /**
691  * Read an amount of bytes at a given offset from the right file. This
692  * abstracts the read-side of the copyonwrite stuff, and calls
693  * rawexpread() with the right parameters to do the actual work.
694  * @param a The offset where the read should start
695  * @param buf A buffer to read into
696  * @param len The size of buf
697  * @param client The client we're going to read for
698  * @return The number of bytes actually read, or -1 in case of an error
699  **/
700 int expread(off_t a, char *buf, size_t len, CLIENT *client) {
701         off_t rdlen, offset;
702         off_t mapcnt, mapl, maph, pagestart;
703
704         if (!(client->server->flags & F_COPYONWRITE))
705                 return rawexpread(a, buf, len, client);
706         DEBUG3("Asked to read %d bytes at %Lu.\n", len, (unsigned long long)a);
707
708         mapl=a/DIFFPAGESIZE; maph=(a+len-1)/DIFFPAGESIZE;
709
710         for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
711                 pagestart=mapcnt*DIFFPAGESIZE;
712                 offset=a-pagestart;
713                 rdlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
714                         len : (size_t)DIFFPAGESIZE-offset;
715                 if (client->difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
716                         DEBUG3("Page %Lu is at %lu\n", (unsigned long long)mapcnt,
717                                (unsigned long)(client->difmap[mapcnt]));
718                         myseek(client->difffile, client->difmap[mapcnt]*DIFFPAGESIZE+offset);
719                         if (read(client->difffile, buf, rdlen) != rdlen) return -1;
720                 } else { /* the block is not there */
721                         DEBUG2("Page %Lu is not here, we read the original one\n",
722                                (unsigned long long)mapcnt);
723                         if(rawexpread(a, buf, rdlen, client)) return -1;
724                 }
725                 len-=rdlen; a+=rdlen; buf+=rdlen;
726         }
727         return 0;
728 }
729
730 /**
731  * Write an amount of bytes at a given offset to the right file. This
732  * abstracts the write-side of the copyonwrite option, and calls
733  * rawexpwrite() with the right parameters to do the actual work.
734  *
735  * @param a The offset where the write should start
736  * @param buf The buffer to write from
737  * @param len The length of buf
738  * @param client The client we're going to write for.
739  * @return The number of bytes actually written, or -1 in case of an error
740  **/
741 int expwrite(off_t a, char *buf, size_t len, CLIENT *client) {
742         char pagebuf[DIFFPAGESIZE];
743         off_t mapcnt,mapl,maph;
744         off_t wrlen,rdlen; 
745         off_t pagestart;
746         off_t offset;
747
748         if (!(client->server->flags & F_COPYONWRITE))
749                 return(rawexpwrite(a,buf,len, client)); 
750         DEBUG3("Asked to write %d bytes at %Lu.\n", len, (unsigned long long)a);
751
752         mapl=a/DIFFPAGESIZE ; maph=(a+len-1)/DIFFPAGESIZE ;
753
754         for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
755                 pagestart=mapcnt*DIFFPAGESIZE ;
756                 offset=a-pagestart ;
757                 wrlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
758                         len : (size_t)DIFFPAGESIZE-offset;
759
760                 if (client->difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
761                         DEBUG3("Page %Lu is at %lu\n", (unsigned long long)mapcnt,
762                                (unsigned long)(client->difmap[mapcnt])) ;
763                         myseek(client->difffile,
764                                         client->difmap[mapcnt]*DIFFPAGESIZE+offset);
765                         if (write(client->difffile, buf, wrlen) != wrlen) return -1 ;
766                 } else { /* the block is not there */
767                         myseek(client->difffile,client->difffilelen*DIFFPAGESIZE) ;
768                         client->difmap[mapcnt]=client->difffilelen++ ;
769                         DEBUG3("Page %Lu is not here, we put it at %lu\n",
770                                (unsigned long long)mapcnt,
771                                (unsigned long)(client->difmap[mapcnt]));
772                         rdlen=DIFFPAGESIZE ;
773                         if (rdlen+pagestart%(client->server->hunksize) >
774                                         (client->server->hunksize)) 
775                                 rdlen=client->server->hunksize -
776                                         (pagestart%client->server->hunksize);
777                         if (rawexpread(pagestart, pagebuf, rdlen, client))
778                                 return -1;
779                         memcpy(pagebuf+offset,buf,wrlen) ;
780                         if (write(client->difffile, pagebuf, DIFFPAGESIZE) !=
781                                         DIFFPAGESIZE)
782                                 return -1;
783                 }                                                   
784                 len-=wrlen ; a+=wrlen ; buf+=wrlen ;
785         }
786         return 0;
787 }
788
789 /**
790  * Do the initial negotiation.
791  *
792  * @param client The client we're negotiating with.
793  **/
794 void negotiate(CLIENT *client) {
795         char zeros[300];
796         u64 size_host;
797
798         memset(zeros, 0, 290);
799         if (write(client->net, INIT_PASSWD, 8) < 0)
800                 err("Negotiation failed: %m");
801         cliserv_magic = htonll(cliserv_magic);
802         if (write(client->net, &cliserv_magic, sizeof(cliserv_magic)) < 0)
803                 err("Negotiation failed: %m");
804         size_host = htonll((u64)(client->exportsize));
805         if (write(client->net, &size_host, 8) < 0)
806                 err("Negotiation failed: %m");
807         if (write(client->net, zeros, 128) < 0)
808                 err("Negotiation failed: %m");
809 }
810
811 /** sending macro. */
812 #define SEND(net,reply) writeit( net, &reply, sizeof( reply ));
813 /** error macro. */
814 #define ERROR(client,reply) { reply.error = htonl(-1); SEND(client->net,reply); reply.error = 0; }
815 /**
816  * Serve a file to a single client.
817  *
818  * @todo This beast needs to be split up in many tiny little manageable
819  * pieces. Preferably with a chainsaw.
820  *
821  * @param client The client we're going to serve to.
822  * @return never
823  **/
824 int mainloop(CLIENT *client) {
825         struct nbd_request request;
826         struct nbd_reply reply;
827         gboolean go_on=TRUE;
828 #ifdef DODBG
829         int i = 0;
830 #endif
831         negotiate(client);
832         DEBUG("Entering request loop!\n");
833         reply.magic = htonl(NBD_REPLY_MAGIC);
834         reply.error = 0;
835         while (go_on) {
836                 char buf[BUFSIZE];
837                 size_t len;
838 #ifdef DODBG
839                 i++;
840                 printf("%d: ", i);
841 #endif
842                 if (client->server->timeout) 
843                         alarm(client->server->timeout);
844                 readit(client->net, &request, sizeof(request));
845                 request.from = ntohll(request.from);
846                 request.type = ntohl(request.type);
847
848                 if (request.type==NBD_CMD_DISC) {
849                         msg2(LOG_INFO, "Disconnect request received.");
850                         if (client->difmap) g_free(client->difmap) ;
851                         if (client->difffile>=0) { 
852                                 close(client->difffile);
853                                 unlink(client->difffilename);
854                                 free(client->difffilename);
855                         }
856                         go_on=FALSE;
857                         continue;
858                 }
859
860                 len = ntohl(request.len);
861
862                 if (request.magic != htonl(NBD_REQUEST_MAGIC))
863                         err("Not enough magic.");
864                 if (len > BUFSIZE + sizeof(struct nbd_reply))
865                         err("Request too big!");
866 #ifdef DODBG
867                 printf("%s from %Lu (%Lu) len %d, ", request.type ? "WRITE" :
868                                 "READ", (unsigned long long)request.from,
869                                 (unsigned long long)request.from / 512, len);
870 #endif
871                 memcpy(reply.handle, request.handle, sizeof(reply.handle));
872                 if ((request.from + len) > (OFFT_MAX)) {
873                         DEBUG("[Number too large!]");
874                         ERROR(client, reply);
875                         continue;
876                 }
877
878                 if (((ssize_t)((off_t)request.from + len) > client->exportsize) ||
879                     ((client->server->flags & F_READONLY) && request.type)) {
880                         DEBUG("[RANGE!]");
881                         ERROR(client, reply);
882                         continue;
883                 }
884
885                 if (request.type==NBD_CMD_WRITE) {
886                         DEBUG("wr: net->buf, ");
887                         readit(client->net, buf, len);
888                         DEBUG("buf->exp, ");
889                         if ((client->server->flags & F_AUTOREADONLY) ||
890                                         expwrite(request.from, buf, len,
891                                                 client)) {
892                                 DEBUG("Write failed: %m" );
893                                 ERROR(client, reply);
894                                 continue;
895                         }
896                         SEND(client->net, reply);
897                         DEBUG("OK!\n");
898                         continue;
899                 }
900                 /* READ */
901
902                 DEBUG("exp->buf, ");
903                 if (expread(request.from, buf + sizeof(struct nbd_reply), len, client)) {
904                         DEBUG("Read failed: %m");
905                         ERROR(client, reply);
906                         continue;
907                 }
908
909                 DEBUG("buf->net, ");
910                 memcpy(buf, &reply, sizeof(struct nbd_reply));
911                 writeit(client->net, buf, len + sizeof(struct nbd_reply));
912                 DEBUG("OK!\n");
913         }
914         return 0;
915 }
916
917 /**
918  * Split a single exportfile into multiple ones, if that was asked.
919  * @return 0 on success, -1 on failure
920  * @param client information on the client which we want to split
921  **/
922 int splitexport(CLIENT* client) {
923         off_t i;
924         int fhandle;
925
926         client->export = g_array_new(TRUE, TRUE, sizeof(int));
927         for (i=0; i<client->exportsize; i+=client->server->hunksize) {
928                 gchar *tmpname;
929
930                 if(client->server->flags & F_MULTIFILE) {
931                         tmpname=g_strdup_printf("%s.%d", client->exportname,
932                                         (int)(i/client->server->hunksize));
933                 } else {
934                         tmpname=g_strdup(client->exportname);
935                 }
936                 DEBUG2( "Opening %s\n", tmpname );
937                 if((fhandle = open(tmpname, (client->server->flags & F_READONLY) ? O_RDONLY : O_RDWR)) == -1) {
938                         /* Read WRITE ACCESS was requested by media is only read only */
939                         client->server->flags |= F_AUTOREADONLY;
940                         client->server->flags |= F_READONLY;
941                         if((fhandle = open(tmpname, O_RDONLY)) == -1)
942                                 err("Could not open exported file: %m");
943                 }
944                 g_array_insert_val(client->export,i/client->server->hunksize,fhandle);
945                 g_free(tmpname);
946         }
947         return 0;
948 }
949
950 int copyonwrite_prepare(CLIENT* client) {
951         off_t i;
952         if ((client->difffilename = malloc(1024))==NULL)
953                 err("Failed to allocate string for diff file name");
954         snprintf(client->difffilename, 1024, "%s-%s-%d.diff",client->exportname,client->clientname,
955                 (int)getpid()) ;
956         client->difffilename[1023]='\0';
957         msg3(LOG_INFO,"About to create map and diff file %s",client->difffilename) ;
958         client->difffile=open(client->difffilename,O_RDWR | O_CREAT | O_TRUNC,0600) ;
959         if (client->difffile<0) err("Could not create diff file (%m)") ;
960         if ((client->difmap=calloc(client->exportsize/DIFFPAGESIZE,sizeof(u32)))==NULL)
961                 err("Could not allocate memory") ;
962         for (i=0;i<client->exportsize/DIFFPAGESIZE;i++) client->difmap[i]=(u32)-1 ;
963
964         return 0;
965 }
966
967 /**
968  * Serve a connection. 
969  *
970  * @todo allow for multithreading, perhaps use libevent. Not just yet, though;
971  * follow the road map.
972  *
973  * @param client a connected client
974  **/
975 void serveconnection(CLIENT *client) {
976         splitexport(client);
977
978         if (!client->server->expected_size) {
979                 client->exportsize = size_autodetect(g_array_index(client->export,int,0));
980         } else {
981                 /* Perhaps we should check first. Not now. */
982                 client->exportsize = client->server->expected_size;
983         }
984         if (client->exportsize > OFFT_MAX) {
985                 /* uhm, well... In a parallel universe, this *might* be
986                  * possible... */
987                 err("Size of exported file is too big\n");
988         }
989         else {
990                 msg3(LOG_INFO, "size of exported file/device is %Lu", (unsigned long long)client->exportsize);
991         }
992
993         if (client->server->flags & F_COPYONWRITE) {
994                 copyonwrite_prepare(client);
995         }
996
997         setmysockopt(client->net);
998
999         mainloop(client);
1000 }
1001
1002 /**
1003  * Find the name of the file we have to serve. This will use g_strdup_printf
1004  * to put the IP address of the client inside a filename containing
1005  * "%s". That name is then written to client->exportname.
1006  *
1007  * @param net A socket connected to an nbd client
1008  * @param client information about the client. The IP address in human-readable
1009  * format will be written to a new char* buffer, the address of which will be
1010  * stored in client->clientname.
1011  **/
1012 void set_peername(int net, CLIENT *client) {
1013         struct sockaddr_in addrin;
1014         int addrinlen = sizeof( addrin );
1015         char *peername ;
1016
1017         if (getpeername(net, (struct sockaddr *) &addrin, (socklen_t *)&addrinlen) < 0)
1018                 err("getsockname failed: %m");
1019         peername = inet_ntoa(addrin.sin_addr);
1020         client->exportname=g_strdup_printf(client->server->exportname, peername);
1021
1022         msg4(LOG_INFO, "connect from %s, assigned file is %s", 
1023              peername, client->exportname);
1024         client->clientname=g_strdup(peername);
1025 }
1026
1027 /**
1028  * Destroy a pid_t*
1029  * @param data a pointer to pid_t which should be freed
1030  **/
1031 void destroy_pid_t(gpointer data) {
1032         g_free(data);
1033 }
1034
1035 /**
1036  * Go daemon (unless we specified at compile time that we didn't want this)
1037  * @param serve the first server of our configuration. If its port is zero,
1038  *      then do not daemonize, because we're doing inetd then. This parameter
1039  *      is only used to create a PID file of the form
1040  *      /var/run/nbd-server.&lt;port&gt;.pid; it's not modified in any way.
1041  **/
1042 #if !defined(NODAEMON) && !defined(NOFORK)
1043 void daemonize(SERVER* serve) {
1044         FILE*pidf;
1045
1046         if(daemon(0,0)<0) {
1047                 err("daemon");
1048         }
1049         if(serve) {
1050                 snprintf(pidfname, sizeof(char)*255, "/var/run/nbd-server.%d.pid", serve->port);
1051         } else {
1052                 strncpy(pidfname, "/var/run/nbd-server.pid", sizeof(char)*255);
1053         }
1054         pidf=fopen(pidfname, "w");
1055         if(pidf) {
1056                 fprintf(pidf,"%d\n", (int)getpid());
1057                 fclose(pidf);
1058         } else {
1059                 perror("fopen");
1060                 fprintf(stderr, "Not fatal; continuing");
1061         }
1062 }
1063 #else
1064 #define daemonize(serve)
1065 #endif /* !defined(NODAEMON) && !defined(NOFORK) */
1066
1067 /**
1068  * Connect a server's socket.
1069  *
1070  * @param serve the server we want to connect.
1071  **/
1072 void setup_serve(SERVER *serve) {
1073         struct sockaddr_in addrin;
1074         struct sigaction sa;
1075         int addrinlen = sizeof(addrin);
1076 #ifndef sun
1077         int yes=1;
1078 #else
1079         char yes='1';
1080 #endif /* sun */
1081         if ((serve->socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
1082                 err("socket: %m");
1083
1084         /* lose the pesky "Address already in use" error message */
1085         if (setsockopt(serve->socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
1086                 err("setsockopt SO_REUSEADDR");
1087         }
1088         if (setsockopt(serve->socket,SOL_SOCKET,SO_KEEPALIVE,&yes,sizeof(int)) == -1) {
1089                 err("setsockopt SO_KEEPALIVE");
1090         }
1091
1092         DEBUG("Waiting for connections... bind, ");
1093         addrin.sin_family = AF_INET;
1094         addrin.sin_port = htons(serve->port);
1095         addrin.sin_addr.s_addr = 0;
1096         if (bind(serve->socket, (struct sockaddr *) &addrin, addrinlen) < 0)
1097                 err("bind: %m");
1098         DEBUG("listen, ");
1099         if (listen(serve->socket, 1) < 0)
1100                 err("listen: %m");
1101         sa.sa_handler = sigchld_handler;
1102         sigemptyset(&sa.sa_mask);
1103         sa.sa_flags = SA_RESTART;
1104         if(sigaction(SIGCHLD, &sa, NULL) == -1)
1105                 err("sigaction: %m");
1106         sa.sa_handler = sigterm_handler;
1107         sigemptyset(&sa.sa_mask);
1108         sa.sa_flags = SA_RESTART;
1109         if(sigaction(SIGTERM, &sa, NULL) == -1)
1110                 err("sigaction: %m");
1111         children=g_hash_table_new_full(g_int_hash, g_int_equal, NULL, destroy_pid_t);
1112 }
1113
1114 /**
1115  * Connect our servers.
1116  **/
1117 void setup_servers(GArray* servers) {
1118         int i;
1119
1120         for(i=0;i<servers->len;i++) {
1121                 setup_serve(&(g_array_index(servers, SERVER, i)));
1122         }
1123 }
1124
1125 /**
1126  * Loop through the available servers, and serve them.
1127  **/
1128 int serveloop(GArray* servers) {
1129         struct sockaddr_in addrin;
1130         socklen_t addrinlen=sizeof(addrin);
1131         SERVER *serve;
1132         int i, max, sock;
1133         fd_set mset, rset;
1134         struct timeval tv;
1135
1136         /* 
1137          * Set up the master fd_set. The set of descriptors we need
1138          * to select() for never changes anyway and it buys us a *lot*
1139          * of time to only build this once. However, if we ever choose
1140          * to not fork() for clients anymore, we may have to revisit
1141          * this.
1142          */
1143         max=0;
1144         FD_ZERO(&mset);
1145         for(i=0;i<servers->len;i++) {
1146                 sock=(g_array_index(servers, SERVER, i)).socket;
1147                 FD_SET(sock, &mset);
1148                 max=sock>max?sock:max;
1149         }
1150         for(;;) {
1151                 CLIENT *client;
1152                 int net;
1153                 pid_t *pid;
1154
1155                 memcpy(&rset, &mset, sizeof(fd_set));
1156                 tv.tv_sec=0;
1157                 tv.tv_usec=500;
1158                 if(select(max+1, &rset, NULL, NULL, &tv)>0) {
1159                         DEBUG("accept, ");
1160                         for(i=0;i<servers->len;i++) {
1161                                 serve=&(g_array_index(servers, SERVER, i));
1162                                 if(FD_ISSET(serve->socket, &rset)) {
1163                                         if ((net=accept(serve->socket, (struct sockaddr *) &addrin, &addrinlen)) < 0)
1164                                                 err("accept: %m");
1165
1166                                         client = g_malloc(sizeof(CLIENT));
1167                                         client->server=serve;
1168                                         client->exportsize=OFFT_MAX;
1169                                         client->net=net;
1170                                         set_peername(net, client);
1171                                         if (!authorized_client(client)) {
1172                                                 msg2(LOG_INFO,"Unauthorized client") ;
1173                                                 close(net);
1174                                                 continue;
1175                                         }
1176                                         msg2(LOG_INFO,"Authorized client") ;
1177                                         pid=g_malloc(sizeof(pid_t));
1178 #ifndef NOFORK
1179                                         if ((*pid=fork())<0) {
1180                                                 msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ;
1181                                                 close(net);
1182                                                 continue;
1183                                         }
1184                                         if (*pid>0) { /* parent */
1185                                                 close(net);
1186                                                 g_hash_table_insert(children, pid, pid);
1187                                                 continue;
1188                                         }
1189                                         /* child */
1190                                         g_hash_table_destroy(children);
1191                                         for(i=0;i<servers->len,serve=(g_array_index(servers, SERVER*, i));i++) {
1192                                                 close(serve->socket);
1193                                         }
1194                                         /* FALSE does not free the
1195                                         actual data. This is required,
1196                                         because the client has a
1197                                         direct reference into that
1198                                         data, and otherwise we get a
1199                                         segfault... */
1200                                         g_array_free(servers, FALSE);
1201 #endif // NOFORK
1202                                         msg2(LOG_INFO,"Starting to serve");
1203                                         serveconnection(client);
1204                                 }
1205                         }
1206                 }
1207         }
1208 }
1209
1210 /**
1211  * Main entry point...
1212  **/
1213 int main(int argc, char *argv[]) {
1214         SERVER *serve;
1215         GArray *servers;
1216         GError *err=NULL;
1217
1218         if (sizeof( struct nbd_request )!=28) {
1219                 fprintf(stderr,"Bad size of structure. Alignment problems?\n");
1220                 exit(-1) ;
1221         }
1222
1223         logging();
1224         config_file_pos = g_strdup(CFILE);
1225         serve=cmdline(argc, argv);
1226         servers = parse_cfile(config_file_pos, &err);
1227         if(!servers || !servers->len) {
1228                 g_warning("Could not parse config file: %s", err->message);
1229         }
1230         if(serve) {
1231                 g_array_append_val(servers, *serve);
1232         }
1233
1234 /* We don't support this at this time */
1235 #if 0
1236         if (!(serve->port)) {
1237                 CLIENT *client;
1238 #ifndef ISSERVER
1239                 /* You really should define ISSERVER if you're going to use
1240                  * inetd mode, but if you don't, closing stdout and stderr
1241                  * (which inetd had connected to the client socket) will let it
1242                  * work. */
1243                 close(1);
1244                 close(2);
1245                 open("/dev/null", O_WRONLY);
1246                 open("/dev/null", O_WRONLY);
1247 #endif
1248                 client=g_malloc(sizeof(CLIENT));
1249                 client->server=serve;
1250                 client->net=0;
1251                 client->exportsize=OFFT_MAX;
1252                 set_peername(0,client);
1253                 serveconnection(client);
1254                 return 0;
1255         }
1256 #endif
1257         if((!serve) && (!servers||!servers->len)) {
1258                 g_message("Nothing to do! Bye!");
1259                 exit(EXIT_FAILURE);
1260         }
1261         daemonize(serve);
1262         setup_servers(servers);
1263         serveloop(servers);
1264         return 0 ;
1265 }