521facc8b72bd76aa3186ed6fca7a65f2aa6448e
[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  * 16/03/2010 - Add IPv6 support.
53  *      Kitt Tientanopajai <kitt@kitty.in.th>
54  *      Neutron Soutmun <neo.neutron@gmail.com>
55  *      Suriya Soutmun <darksolar@gmail.com>
56  */
57
58 /* Includes LFS defines, which defines behaviours of some of the following
59  * headers, so must come before those */
60 #include "lfs.h"
61
62 #include <sys/types.h>
63 #include <sys/socket.h>
64 #include <sys/stat.h>
65 #include <sys/select.h>         /* select */
66 #include <sys/wait.h>           /* wait */
67 #ifdef HAVE_SYS_IOCTL_H
68 #include <sys/ioctl.h>
69 #endif
70 #include <sys/param.h>
71 #ifdef HAVE_SYS_MOUNT_H
72 #include <sys/mount.h>          /* For BLKGETSIZE */
73 #endif
74 #include <signal.h>             /* sigaction */
75 #include <errno.h>
76 #include <netinet/tcp.h>
77 #include <netinet/in.h>
78 #include <netdb.h>
79 #include <syslog.h>
80 #include <unistd.h>
81 #include <stdio.h>
82 #include <stdlib.h>
83 #include <string.h>
84 #include <fcntl.h>
85 #include <arpa/inet.h>
86 #include <strings.h>
87 #include <dirent.h>
88 #include <unistd.h>
89 #include <getopt.h>
90 #include <pwd.h>
91 #include <grp.h>
92
93 #include <glib.h>
94
95 /* used in cliserv.h, so must come first */
96 #define MY_NAME "nbd_server"
97 #include "cliserv.h"
98
99 /** Default position of the config file */
100 #ifndef SYSCONFDIR
101 #define SYSCONFDIR "/etc"
102 #endif
103 #define CFILE SYSCONFDIR "/nbd-server/config"
104
105 /** Where our config file actually is */
106 gchar* config_file_pos;
107
108 /** What user we're running as */
109 gchar* runuser=NULL;
110 /** What group we're running as */
111 gchar* rungroup=NULL;
112
113 /** Logging macros, now nothing goes to syslog unless you say ISSERVER */
114 #ifdef ISSERVER
115 #define msg2(a,b) syslog(a,b)
116 #define msg3(a,b,c) syslog(a,b,c)
117 #define msg4(a,b,c,d) syslog(a,b,c,d)
118 #else
119 #define msg2(a,b) g_message(b)
120 #define msg3(a,b,c) g_message(b,c)
121 #define msg4(a,b,c,d) g_message(b,c,d)
122 #endif
123
124 /* Debugging macros */
125 //#define DODBG
126 #ifdef DODBG
127 #define DEBUG( a ) printf( a )
128 #define DEBUG2( a,b ) printf( a,b )
129 #define DEBUG3( a,b,c ) printf( a,b,c )
130 #define DEBUG4( a,b,c,d ) printf( a,b,c,d )
131 #else
132 #define DEBUG( a )
133 #define DEBUG2( a,b ) 
134 #define DEBUG3( a,b,c ) 
135 #define DEBUG4( a,b,c,d ) 
136 #endif
137 #ifndef PACKAGE_VERSION
138 #define PACKAGE_VERSION ""
139 #endif
140 /**
141  * The highest value a variable of type off_t can reach. This is a signed
142  * integer, so set all bits except for the leftmost one.
143  **/
144 #define OFFT_MAX ~((off_t)1<<(sizeof(off_t)*8-1))
145 #define LINELEN 256       /**< Size of static buffer used to read the
146                                authorization file (yuck) */
147 #define BUFSIZE (1024*1024) /**< Size of buffer that can hold requests */
148 #define DIFFPAGESIZE 4096 /**< diff file uses those chunks */
149 #define F_READONLY 1      /**< flag to tell us a file is readonly */
150 #define F_MULTIFILE 2     /**< flag to tell us a file is exported using -m */
151 #define F_COPYONWRITE 4   /**< flag to tell us a file is exported using
152                             copyonwrite */
153 #define F_AUTOREADONLY 8  /**< flag to tell us a file is set to autoreadonly */
154 #define F_SPARSE 16       /**< flag to tell us copyronwrite should use a sparse file */
155 #define F_SDP 32          /**< flag to tell us the export should be done using the Socket Direct Protocol for RDMA */
156 #define F_SYNC 64         /**< Whether to fsync() after a write */
157 GHashTable *children;
158 char pidfname[256]; /**< name of our PID file */
159 char pidftemplate[256]; /**< template to be used for the filename of the PID file */
160 char default_authname[] = SYSCONFDIR "/nbd-server/allow"; /**< default name of allow file */
161
162 /**
163  * Types of virtuatlization
164  **/
165 typedef enum {
166         VIRT_NONE=0,    /**< No virtualization */
167         VIRT_IPLIT,     /**< Literal IP address as part of the filename */
168         VIRT_IPHASH,    /**< Replacing all dots in an ip address by a / before
169                              doing the same as in IPLIT */
170         VIRT_CIDR,      /**< Every subnet in its own directory */
171 } VIRT_STYLE;
172
173 /**
174  * Variables associated with a server.
175  **/
176 typedef struct {
177         gchar* exportname;    /**< (unprocessed) filename of the file we're exporting */
178         off_t expected_size; /**< size of the exported file as it was told to
179                                us through configuration */
180         gchar* listenaddr;   /**< The IP address we're listening on */
181         unsigned int port;   /**< port we're exporting this file at */
182         char* authname;      /**< filename of the authorization file */
183         int flags;           /**< flags associated with this exported file */
184         int socket;          /**< The socket of this server. */
185         int socket_family;   /**< family of the socket */
186         VIRT_STYLE virtstyle;/**< The style of virtualization, if any */
187         uint8_t cidrlen;     /**< The length of the mask when we use
188                                   CIDR-style virtualization */
189         gchar* prerun;       /**< command to be ran after connecting a client,
190                                   but before starting to serve */
191         gchar* postrun;      /**< command that will be ran after the client
192                                   disconnects */
193 } SERVER;
194
195 /**
196  * Variables associated with a client socket.
197  **/
198 typedef struct {
199         int fhandle;      /**< file descriptor */
200         off_t startoff;   /**< starting offset of this file */
201 } FILE_INFO;
202
203 typedef struct {
204         off_t exportsize;    /**< size of the file we're exporting */
205         char *clientname;    /**< peer */
206         char *exportname;    /**< (processed) filename of the file we're exporting */
207         GArray *export;    /**< array of FILE_INFO of exported files;
208                                array size is always 1 unless we're
209                                doing the multiple file option */
210         int net;             /**< The actual client socket */
211         SERVER *server;      /**< The server this client is getting data from */
212         char* difffilename;  /**< filename of the copy-on-write file, if any */
213         int difffile;        /**< filedescriptor of copyonwrite file. @todo
214                                shouldn't this be an array too? (cfr export) Or
215                                make -m and -c mutually exclusive */
216         u32 difffilelen;     /**< number of pages in difffile */
217         u32 *difmap;         /**< see comment on the global difmap for this one */
218 } CLIENT;
219
220 /**
221  * Type of configuration file values
222  **/
223 typedef enum {
224         PARAM_INT,              /**< This parameter is an integer */
225         PARAM_STRING,           /**< This parameter is a string */
226         PARAM_BOOL,             /**< This parameter is a boolean */
227 } PARAM_TYPE;
228
229 /**
230  * Configuration file values
231  **/
232 typedef struct {
233         gchar *paramname;       /**< Name of the parameter, as it appears in
234                                   the config file */
235         gboolean required;      /**< Whether this is a required (as opposed to
236                                   optional) parameter */
237         PARAM_TYPE ptype;       /**< Type of the parameter. */
238         gpointer target;        /**< Pointer to where the data of this
239                                   parameter should be written. If ptype is
240                                   PARAM_BOOL, the data is or'ed rather than
241                                   overwritten. */
242         gint flagval;           /**< Flag mask for this parameter in case ptype
243                                   is PARAM_BOOL. */
244 } PARAM;
245
246 /**
247  * Check whether a client is allowed to connect. Works with an authorization
248  * file which contains one line per machine, no wildcards.
249  *
250  * @param opts The client who's trying to connect.
251  * @return 0 - authorization refused, 1 - OK
252  **/
253 int authorized_client(CLIENT *opts) {
254         const char *ERRMSG="Invalid entry '%s' in authfile '%s', so, refusing all connections.";
255         FILE *f ;
256         char line[LINELEN]; 
257         char *tmp;
258         struct in_addr addr;
259         struct in_addr client;
260         struct in_addr cltemp;
261         int len;
262
263         if ((f=fopen(opts->server->authname,"r"))==NULL) {
264                 msg4(LOG_INFO,"Can't open authorization file %s (%s).",
265                      opts->server->authname,strerror(errno)) ;
266                 return 1 ; 
267         }
268   
269         inet_aton(opts->clientname, &client);
270         while (fgets(line,LINELEN,f)!=NULL) {
271                 if((tmp=index(line, '/'))) {
272                         if(strlen(line)<=tmp-line) {
273                                 msg4(LOG_CRIT, ERRMSG, line, opts->server->authname);
274                                 return 0;
275                         }
276                         *(tmp++)=0;
277                         if(inet_aton(line,&addr)) {
278                                 msg4(LOG_CRIT, ERRMSG, line, opts->server->authname);
279                                 return 0;
280                         }
281                         len=strtol(tmp, NULL, 0);
282                         addr.s_addr>>=32-len;
283                         addr.s_addr<<=32-len;
284                         memcpy(&cltemp,&client,sizeof(client));
285                         cltemp.s_addr>>=32-len;
286                         cltemp.s_addr<<=32-len;
287                         if(addr.s_addr == cltemp.s_addr) {
288                                 return 1;
289                         }
290                 }
291                 if (strncmp(line,opts->clientname,strlen(opts->clientname))==0) {
292                         fclose(f);
293                         return 1;
294                 }
295         }
296         fclose(f);
297         return 0;
298 }
299
300 /**
301  * Read data from a file descriptor into a buffer
302  *
303  * @param f a file descriptor
304  * @param buf a buffer
305  * @param len the number of bytes to be read
306  **/
307 inline void readit(int f, void *buf, size_t len) {
308         ssize_t res;
309         while (len > 0) {
310                 DEBUG("*");
311                 if ((res = read(f, buf, len)) <= 0) {
312                         if(errno != EAGAIN) {
313                                 err("Read failed: %m");
314                         }
315                 } else {
316                         len -= res;
317                         buf += res;
318                 }
319         }
320 }
321
322 /**
323  * Write data from a buffer into a filedescriptor
324  *
325  * @param f a file descriptor
326  * @param buf a buffer containing data
327  * @param len the number of bytes to be written
328  **/
329 inline void writeit(int f, void *buf, size_t len) {
330         ssize_t res;
331         while (len > 0) {
332                 DEBUG("+");
333                 if ((res = write(f, buf, len)) <= 0)
334                         err("Send failed: %m");
335                 len -= res;
336                 buf += res;
337         }
338 }
339
340 /**
341  * Print out a message about how to use nbd-server. Split out to a separate
342  * function so that we can call it from multiple places
343  */
344 void usage() {
345         printf("This is nbd-server version " VERSION "\n");
346         printf("Usage: [ip:|ip6@]port file_to_export [size][kKmM] [-l authorize_file] [-r] [-m] [-c] [-C configuration file] [-p PID file name] [-o section name]\n"
347                "\t-r|--read-only\t\tread only\n"
348                "\t-m|--multi-file\t\tmultiple file\n"
349                "\t-c|--copy-on-write\tcopy on write\n"
350                "\t-C|--config-file\tspecify an alternate configuration file\n"
351                "\t-l|--authorize-file\tfile with list of hosts that are allowed to\n\t\t\t\tconnect.\n"
352                "\t-p|--pid-file\t\tspecify a filename to write our PID to\n"
353                "\t-o|--output-config\toutput a config file section for what you\n\t\t\t\tspecified on the command line, with the\n\t\t\t\tspecified section name\n\n"
354                "\tif port is set to 0, stdin is used (for running from inetd)\n"
355                "\tif file_to_export contains '%%s', it is substituted with the IP\n"
356                "\t\taddress of the machine trying to connect\n" 
357                "\tif ip is set, it contains the local IP address on which we're listening.\n\tif not, the server will listen on all local IP addresses\n");
358         printf("Using configuration file %s\n", CFILE);
359 }
360
361 /* Dumps a config file section of the given SERVER*, and exits. */
362 void dump_section(SERVER* serve, gchar* section_header) {
363         printf("[%s]\n", section_header);
364         printf("\texportname = %s\n", serve->exportname);
365         printf("\tlistenaddr = %s\n", serve->listenaddr);
366         printf("\tport = %d\n", serve->port);
367         if(serve->flags & F_READONLY) {
368                 printf("\treadonly = true\n");
369         }
370         if(serve->flags & F_MULTIFILE) {
371                 printf("\tmultifile = true\n");
372         }
373         if(serve->flags & F_COPYONWRITE) {
374                 printf("\tcopyonwrite = true\n");
375         }
376         if(serve->expected_size) {
377                 printf("\tfilesize = %lld\n", (long long int)serve->expected_size);
378         }
379         if(serve->authname) {
380                 printf("\tauthfile = %s\n", serve->authname);
381         }
382         exit(EXIT_SUCCESS);
383 }
384
385 /**
386  * Parse the command line.
387  *
388  * @param argc the argc argument to main()
389  * @param argv the argv argument to main()
390  **/
391 SERVER* cmdline(int argc, char *argv[]) {
392         int i=0;
393         int nonspecial=0;
394         int c;
395         struct option long_options[] = {
396                 {"read-only", no_argument, NULL, 'r'},
397                 {"multi-file", no_argument, NULL, 'm'},
398                 {"copy-on-write", no_argument, NULL, 'c'},
399                 {"authorize-file", required_argument, NULL, 'l'},
400                 {"config-file", required_argument, NULL, 'C'},
401                 {"pid-file", required_argument, NULL, 'p'},
402                 {"output-config", required_argument, NULL, 'o'},
403                 {0,0,0,0}
404         };
405         SERVER *serve;
406         off_t es;
407         size_t last;
408         char suffix;
409         gboolean do_output=FALSE;
410         gchar* section_header="";
411         gchar** addr_port;
412
413         if(argc==1) {
414                 return NULL;
415         }
416         serve=g_new0(SERVER, 1);
417         serve->authname = g_strdup(default_authname);
418         serve->virtstyle=VIRT_IPLIT;
419         while((c=getopt_long(argc, argv, "-C:cl:mo:rp:", long_options, &i))>=0) {
420                 switch (c) {
421                 case 1:
422                         /* non-option argument */
423                         switch(nonspecial++) {
424                         case 0:
425                                 if(strchr(optarg, ':') == strrchr(optarg, ':')) {
426                                         addr_port=g_strsplit(optarg, ":", 2);
427
428                                         /* Check for "@" - maybe user using this separator
429                                                  for IPv4 address */
430                                         if(!addr_port[1]) {
431                                                 g_strfreev(addr_port);
432                                                 addr_port=g_strsplit(optarg, "@", 2);
433                                         }
434                                 } else {
435                                         addr_port=g_strsplit(optarg, "@", 2);
436                                 }
437
438                                 if(addr_port[1]) {
439                                         serve->port=strtol(addr_port[1], NULL, 0);
440                                         serve->listenaddr=g_strdup(addr_port[0]);
441                                 } else {
442                                         serve->listenaddr=NULL;
443                                         serve->port=strtol(addr_port[0], NULL, 0);
444                                 }
445                                 g_strfreev(addr_port);
446                                 break;
447                         case 1:
448                                 serve->exportname = g_strdup(optarg);
449                                 if(serve->exportname[0] != '/') {
450                                         fprintf(stderr, "E: The to be exported file needs to be an absolute filename!\n");
451                                         exit(EXIT_FAILURE);
452                                 }
453                                 break;
454                         case 2:
455                                 last=strlen(optarg)-1;
456                                 suffix=optarg[last];
457                                 if (suffix == 'k' || suffix == 'K' ||
458                                     suffix == 'm' || suffix == 'M')
459                                         optarg[last] = '\0';
460                                 es = (off_t)atoll(optarg);
461                                 switch (suffix) {
462                                         case 'm':
463                                         case 'M':  es <<= 10;
464                                         case 'k':
465                                         case 'K':  es <<= 10;
466                                         default :  break;
467                                 }
468                                 serve->expected_size = es;
469                                 break;
470                         }
471                         break;
472                 case 'r':
473                         serve->flags |= F_READONLY;
474                         break;
475                 case 'm':
476                         serve->flags |= F_MULTIFILE;
477                         break;
478                 case 'o':
479                         do_output = TRUE;
480                         section_header = g_strdup(optarg);
481                         break;
482                 case 'p':
483                         strncpy(pidftemplate, optarg, 256);
484                         break;
485                 case 'c': 
486                         serve->flags |=F_COPYONWRITE;
487                         break;
488                 case 'C':
489                         g_free(config_file_pos);
490                         config_file_pos=g_strdup(optarg);
491                         break;
492                 case 'l':
493                         g_free(serve->authname);
494                         serve->authname=g_strdup(optarg);
495                         break;
496                 default:
497                         usage();
498                         exit(EXIT_FAILURE);
499                         break;
500                 }
501         }
502         /* What's left: the port to export, the name of the to be exported
503          * file, and, optionally, the size of the file, in that order. */
504         if(nonspecial<2) {
505                 g_free(serve);
506                 serve=NULL;
507         }
508         if(do_output) {
509                 if(!serve) {
510                         g_critical("Need a complete configuration on the command line to output a config file section!");
511                         exit(EXIT_FAILURE);
512                 }
513                 dump_section(serve, section_header);
514         }
515         return serve;
516 }
517
518 /**
519  * Error codes for config file parsing
520  **/
521 typedef enum {
522         CFILE_NOTFOUND,         /**< The configuration file is not found */
523         CFILE_MISSING_GENERIC,  /**< The (required) group "generic" is missing */
524         CFILE_KEY_MISSING,      /**< A (required) key is missing */
525         CFILE_VALUE_INVALID,    /**< A value is syntactically invalid */
526         CFILE_VALUE_UNSUPPORTED,/**< A value is not supported in this build */
527         CFILE_PROGERR,          /**< Programmer error */
528         CFILE_NO_EXPORTS        /**< A config file was specified that does not
529                                      define any exports */
530 } CFILE_ERRORS;
531
532 /**
533  * Remove a SERVER from memory. Used from the hash table
534  **/
535 void remove_server(gpointer s) {
536         SERVER *server;
537
538         server=(SERVER*)s;
539         g_free(server->exportname);
540         if(server->authname)
541                 g_free(server->authname);
542         g_free(server);
543 }
544
545 /**
546  * duplicate server
547  * @param s the old server we want to duplicate
548  * @return new duplicated server
549  **/
550 SERVER* dup_serve(SERVER *s) {
551         SERVER *serve = NULL;
552
553         serve=g_new0(SERVER, 1);
554         if (serve == NULL)
555                 return NULL;
556
557         if (s->exportname)
558                 serve->exportname = g_strdup(s->exportname);
559
560         serve->expected_size = s->expected_size;
561
562         if (s->listenaddr)
563                 serve->listenaddr = g_strdup(s->listenaddr);
564
565         serve->port = s->port;
566
567         if (s->authname)
568                 serve->authname = strdup(s->authname);
569
570         serve->flags = s->flags;
571         serve->socket = serve->socket;
572         serve->socket_family = serve->socket_family;
573         serve->cidrlen = s->cidrlen;
574
575         if (s->prerun)
576                 serve->prerun = g_strdup(s->prerun);
577
578         if (s->postrun)
579                 serve->postrun = g_strdup(s->postrun);
580
581         return serve;
582 }
583
584 /**
585  * append new server to array
586  * @param s server
587  * @param a server array
588  * @return 0 success, -1 error
589  */
590 int append_serve(SERVER *s, GArray *a)
591 {
592         SERVER *ns = NULL;
593         struct addrinfo hints;
594         struct addrinfo *ai = NULL;
595         struct addrinfo *rp = NULL;
596         char   host[NI_MAXHOST];
597         gchar  *port = NULL;
598         int e;
599         int ret;
600
601         if(!s) {
602                 err("Invalid parsing server");
603                 return -1;
604         }
605
606         port = g_strdup_printf("%d", s->port);
607
608         memset(&hints,'\0',sizeof(hints));
609         hints.ai_family = AF_UNSPEC;
610         hints.ai_socktype = SOCK_STREAM;
611         hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
612         hints.ai_protocol = IPPROTO_TCP;
613
614         e = getaddrinfo(s->listenaddr, port, &hints, &ai);
615
616         if (port)
617                 g_free(port);
618
619         if(e == 0) {
620                 for (rp = ai; rp != NULL; rp = rp->ai_next) {
621                         e = getnameinfo(rp->ai_addr, rp->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
622
623                         if (e != 0) { // error
624                                 fprintf(stderr, "getnameinfo: %s\n", gai_strerror(e));
625                                 continue;
626                         }
627
628                         // duplicate server and set listenaddr to resolved IP address
629                         ns = dup_serve (s);
630                         if (ns) {
631                                 ns->listenaddr = g_strdup(host);
632                                 ns->socket_family = rp->ai_family;
633                                 g_array_append_val(a, *ns);
634                                 free(ns);
635                                 ns = NULL;
636                         }
637                 }
638
639                 ret = 0;
640         } else {
641                 fprintf(stderr, "getaddrinfo failed on listen host/address: %s (%s)\n", s->listenaddr ? s->listenaddr : "any", gai_strerror(e));
642                 ret = -1;
643         }
644
645         if (ai)
646                 freeaddrinfo(ai);
647
648         return ret;
649 }
650
651 /**
652  * Parse the config file.
653  *
654  * @param f the name of the config file
655  * @param e a GError. @see CFILE_ERRORS for what error values this function can
656  *      return.
657  * @return a Array of SERVER* pointers, If the config file is empty or does not
658  *      exist, returns an empty GHashTable; if the config file contains an
659  *      error, returns NULL, and e is set appropriately
660  **/
661 GArray* parse_cfile(gchar* f, GError** e) {
662         const char* DEFAULT_ERROR = "Could not parse %s in group %s: %s";
663         const char* MISSING_REQUIRED_ERROR = "Could not find required value %s in group %s: %s";
664         SERVER s;
665         gchar *virtstyle=NULL;
666         PARAM lp[] = {
667                 { "exportname", TRUE,   PARAM_STRING,   NULL, 0 },
668                 { "port",       TRUE,   PARAM_INT,      NULL, 0 },
669                 { "authfile",   FALSE,  PARAM_STRING,   NULL, 0 },
670                 { "filesize",   FALSE,  PARAM_INT,      NULL, 0 },
671                 { "virtstyle",  FALSE,  PARAM_STRING,   NULL, 0 },
672                 { "prerun",     FALSE,  PARAM_STRING,   NULL, 0 },
673                 { "postrun",    FALSE,  PARAM_STRING,   NULL, 0 },
674                 { "readonly",   FALSE,  PARAM_BOOL,     NULL, F_READONLY },
675                 { "multifile",  FALSE,  PARAM_BOOL,     NULL, F_MULTIFILE },
676                 { "copyonwrite", FALSE, PARAM_BOOL,     NULL, F_COPYONWRITE },
677                 { "sparse_cow", FALSE,  PARAM_BOOL,     NULL, F_SPARSE },
678                 { "sdp",        FALSE,  PARAM_BOOL,     NULL, F_SDP },
679                 { "sync",       FALSE,  PARAM_BOOL,     NULL, F_SYNC },
680                 { "listenaddr", FALSE,  PARAM_STRING,   NULL, 0 },
681         };
682         const int lp_size=sizeof(lp)/sizeof(PARAM);
683         PARAM gp[] = {
684                 { "user",       FALSE, PARAM_STRING,    &runuser,       0 },
685                 { "group",      FALSE, PARAM_STRING,    &rungroup,      0 },
686         };
687         PARAM* p=gp;
688         int p_size=sizeof(gp)/sizeof(PARAM);
689         GKeyFile *cfile;
690         GError *err = NULL;
691         const char *err_msg=NULL;
692         GQuark errdomain;
693         GArray *retval=NULL;
694         gchar **groups;
695         gboolean value;
696         gchar* startgroup;
697         gint i;
698         gint j;
699
700         errdomain = g_quark_from_string("parse_cfile");
701         cfile = g_key_file_new();
702         retval = g_array_new(FALSE, TRUE, sizeof(SERVER));
703         if(!g_key_file_load_from_file(cfile, f, G_KEY_FILE_KEEP_COMMENTS |
704                         G_KEY_FILE_KEEP_TRANSLATIONS, &err)) {
705                 g_set_error(e, errdomain, CFILE_NOTFOUND, "Could not open config file %s.", f);
706                 g_key_file_free(cfile);
707                 return retval;
708         }
709         startgroup = g_key_file_get_start_group(cfile);
710         if(!startgroup || strcmp(startgroup, "generic")) {
711                 g_set_error(e, errdomain, CFILE_MISSING_GENERIC, "Config file does not contain the [generic] group!");
712                 g_key_file_free(cfile);
713                 return NULL;
714         }
715         groups = g_key_file_get_groups(cfile, NULL);
716         for(i=0;groups[i];i++) {
717                 memset(&s, '\0', sizeof(SERVER));
718                 lp[0].target=&(s.exportname);
719                 lp[1].target=&(s.port);
720                 lp[2].target=&(s.authname);
721                 lp[3].target=&(s.expected_size);
722                 lp[4].target=&(virtstyle);
723                 lp[5].target=&(s.prerun);
724                 lp[6].target=&(s.postrun);
725                 lp[7].target=lp[8].target=lp[9].target=
726                                 lp[10].target=lp[11].target=
727                                 lp[12].target=&(s.flags);
728                 lp[13].target=&(s.listenaddr);
729
730                 /* After the [generic] group, start parsing exports */
731                 if(i==1) {
732                         p=lp;
733                         p_size=lp_size;
734                 } 
735                 for(j=0;j<p_size;j++) {
736                         g_assert(p[j].target != NULL);
737                         g_assert(p[j].ptype==PARAM_INT||p[j].ptype==PARAM_STRING||p[j].ptype==PARAM_BOOL);
738                         switch(p[j].ptype) {
739                                 case PARAM_INT:
740                                         *((gint*)p[j].target) =
741                                                 g_key_file_get_integer(cfile,
742                                                                 groups[i],
743                                                                 p[j].paramname,
744                                                                 &err);
745                                         break;
746                                 case PARAM_STRING:
747                                         *((gchar**)p[j].target) =
748                                                 g_key_file_get_string(cfile,
749                                                                 groups[i],
750                                                                 p[j].paramname,
751                                                                 &err);
752                                         break;
753                                 case PARAM_BOOL:
754                                         value = g_key_file_get_boolean(cfile,
755                                                         groups[i],
756                                                         p[j].paramname, &err);
757                                         if(!err) {
758                                                 if(value) {
759                                                         *((gint*)p[j].target) |= p[j].flagval;
760                                                 } else {
761                                                         *((gint*)p[j].target) &= ~(p[j].flagval);
762                                                 }
763                                         }
764                                         break;
765                         }
766                         if(err) {
767                                 if(err->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
768                                         if(!p[j].required) {
769                                                 /* Ignore not-found error for optional values */
770                                                 g_clear_error(&err);
771                                                 continue;
772                                         } else {
773                                                 err_msg = MISSING_REQUIRED_ERROR;
774                                         }
775                                 } else {
776                                         err_msg = DEFAULT_ERROR;
777                                 }
778                                 g_set_error(e, errdomain, CFILE_VALUE_INVALID, err_msg, p[j].paramname, groups[i], err->message);
779                                 g_array_free(retval, TRUE);
780                                 g_error_free(err);
781                                 g_key_file_free(cfile);
782                                 return NULL;
783                         }
784                 }
785                 if(virtstyle) {
786                         if(!strncmp(virtstyle, "none", 4)) {
787                                 s.virtstyle=VIRT_NONE;
788                         } else if(!strncmp(virtstyle, "ipliteral", 9)) {
789                                 s.virtstyle=VIRT_IPLIT;
790                         } else if(!strncmp(virtstyle, "iphash", 6)) {
791                                 s.virtstyle=VIRT_IPHASH;
792                         } else if(!strncmp(virtstyle, "cidrhash", 8)) {
793                                 s.virtstyle=VIRT_CIDR;
794                                 if(strlen(virtstyle)<10) {
795                                         g_set_error(e, errdomain, CFILE_VALUE_INVALID, "Invalid value %s for parameter virtstyle in group %s: missing length", virtstyle, groups[i]);
796                                         g_array_free(retval, TRUE);
797                                         g_key_file_free(cfile);
798                                         return NULL;
799                                 }
800                                 s.cidrlen=strtol(virtstyle+8, NULL, 0);
801                         } else {
802                                 g_set_error(e, errdomain, CFILE_VALUE_INVALID, "Invalid value %s for parameter virtstyle in group %s", virtstyle, groups[i]);
803                                 g_array_free(retval, TRUE);
804                                 g_key_file_free(cfile);
805                                 return NULL;
806                         }
807                 } else {
808                         s.virtstyle=VIRT_IPLIT;
809                 }
810                 /* Don't need to free this, it's not our string */
811                 virtstyle=NULL;
812                 /* Don't append values for the [generic] group */
813                 if(i>0) {
814                         s.socket_family = AF_UNSPEC;
815
816                         append_serve(&s, retval);
817                 }
818 #ifndef WITH_SDP
819                 if(s.flags & F_SDP) {
820                         g_set_error(e, errdomain, CFILE_VALUE_UNSUPPORTED, "This nbd-server was built without support for SDP, yet group %s uses it", groups[i]);
821                         g_array_free(retval, TRUE);
822                         g_key_file_free(cfile);
823                         return NULL;
824                 }
825 #endif
826         }
827         if(i==1) {
828                 g_set_error(e, errdomain, CFILE_NO_EXPORTS, "The config file does not specify any exports");
829         }
830         g_key_file_free(cfile);
831         return retval;
832 }
833
834 /**
835  * Signal handler for SIGCHLD
836  * @param s the signal we're handling (must be SIGCHLD, or something
837  * is severely wrong)
838  **/
839 void sigchld_handler(int s) {
840         int status;
841         int* i;
842         pid_t pid;
843
844         while((pid=waitpid(-1, &status, WNOHANG)) > 0) {
845                 if(WIFEXITED(status)) {
846                         msg3(LOG_INFO, "Child exited with %d", WEXITSTATUS(status));
847                 }
848                 i=g_hash_table_lookup(children, &pid);
849                 if(!i) {
850                         msg3(LOG_INFO, "SIGCHLD received for an unknown child with PID %ld", (long)pid);
851                 } else {
852                         DEBUG2("Removing %d from the list of children", pid);
853                         g_hash_table_remove(children, &pid);
854                 }
855         }
856 }
857
858 /**
859  * Kill a child. Called from sigterm_handler::g_hash_table_foreach.
860  *
861  * @param key the key
862  * @param value the value corresponding to the above key
863  * @param user_data a pointer which we always set to 1, so that we know what
864  * will happen next.
865  **/
866 void killchild(gpointer key, gpointer value, gpointer user_data) {
867         pid_t *pid=value;
868         int *parent=user_data;
869
870         kill(*pid, SIGTERM);
871         *parent=1;
872 }
873
874 /**
875  * Handle SIGTERM and dispatch it to our children
876  * @param s the signal we're handling (must be SIGTERM, or something
877  * is severely wrong).
878  **/
879 void sigterm_handler(int s) {
880         int parent=0;
881
882         g_hash_table_foreach(children, killchild, &parent);
883
884         if(parent) {
885                 unlink(pidfname);
886         }
887
888         exit(EXIT_SUCCESS);
889 }
890
891 /**
892  * Detect the size of a file.
893  *
894  * @param fhandle An open filedescriptor
895  * @return the size of the file, or OFFT_MAX if detection was
896  * impossible.
897  **/
898 off_t size_autodetect(int fhandle) {
899         off_t es;
900         u64 bytes;
901         struct stat stat_buf;
902         int error;
903
904 #ifdef HAVE_SYS_MOUNT_H
905 #ifdef HAVE_SYS_IOCTL_H
906 #ifdef BLKGETSIZE64
907         DEBUG("looking for export size with ioctl BLKGETSIZE64\n");
908         if (!ioctl(fhandle, BLKGETSIZE64, bytes) && bytes) {
909                 return (off_t)bytes;
910         }
911 #endif /* BLKGETSIZE64 */
912 #endif /* HAVE_SYS_IOCTL_H */
913 #endif /* HAVE_SYS_MOUNT_H */
914
915         DEBUG("looking for fhandle size with fstat\n");
916         stat_buf.st_size = 0;
917         error = fstat(fhandle, &stat_buf);
918         if (!error) {
919                 if(stat_buf.st_size > 0)
920                         return (off_t)stat_buf.st_size;
921         } else {
922                 err("fstat failed: %m");
923         }
924
925         DEBUG("looking for fhandle size with lseek SEEK_END\n");
926         es = lseek(fhandle, (off_t)0, SEEK_END);
927         if (es > ((off_t)0)) {
928                 return es;
929         } else {
930                 DEBUG2("lseek failed: %d", errno==EBADF?1:(errno==ESPIPE?2:(errno==EINVAL?3:4)));
931         }
932
933         err("Could not find size of exported block device: %m");
934         return OFFT_MAX;
935 }
936
937 /**
938  * Get the file handle and offset, given an export offset.
939  *
940  * @param export An array of export files
941  * @param a The offset to get corresponding file/offset for
942  * @param fhandle [out] File descriptor
943  * @param foffset [out] Offset into fhandle
944  * @param maxbytes [out] Tells how many bytes can be read/written
945  * from fhandle starting at foffset (0 if there is no limit)
946  * @return 0 on success, -1 on failure
947  **/
948 int get_filepos(GArray* export, off_t a, int* fhandle, off_t* foffset, size_t* maxbytes ) {
949         /* Negative offset not allowed */
950         if(a < 0)
951                 return -1;
952
953         /* Binary search for last file with starting offset <= a */
954         FILE_INFO fi;
955         int start = 0;
956         int end = export->len - 1;
957         while( start <= end ) {
958                 int mid = (start + end) / 2;
959                 fi = g_array_index(export, FILE_INFO, mid);
960                 if( fi.startoff < a ) {
961                         start = mid + 1;
962                 } else if( fi.startoff > a ) {
963                         end = mid - 1;
964                 } else {
965                         start = end = mid;
966                         break;
967                 }
968         }
969
970         /* end should never go negative, since first startoff is 0 and a >= 0 */
971         g_assert(end >= 0);
972
973         fi = g_array_index(export, FILE_INFO, end);
974         *fhandle = fi.fhandle;
975         *foffset = a - fi.startoff;
976         *maxbytes = 0;
977         if( end+1 < export->len ) {
978                 FILE_INFO fi_next = g_array_index(export, FILE_INFO, end+1);
979                 *maxbytes = fi_next.startoff - a;
980         }
981
982         return 0;
983 }
984
985 /**
986  * seek to a position in a file, with error handling.
987  * @param handle a filedescriptor
988  * @param a position to seek to
989  * @todo get rid of this; lastpoint is a global variable right now, but it
990  * shouldn't be. If we pass it on as a parameter, that makes things a *lot*
991  * easier.
992  **/
993 void myseek(int handle,off_t a) {
994         if (lseek(handle, a, SEEK_SET) < 0) {
995                 err("Can not seek locally!\n");
996         }
997 }
998
999 /**
1000  * Write an amount of bytes at a given offset to the right file. This
1001  * abstracts the write-side of the multiple file option.
1002  *
1003  * @param a The offset where the write should start
1004  * @param buf The buffer to write from
1005  * @param len The length of buf
1006  * @param client The client we're serving for
1007  * @return The number of bytes actually written, or -1 in case of an error
1008  **/
1009 ssize_t rawexpwrite(off_t a, char *buf, size_t len, CLIENT *client) {
1010         int fhandle;
1011         off_t foffset;
1012         size_t maxbytes;
1013         ssize_t retval;
1014
1015         if(get_filepos(client->export, a, &fhandle, &foffset, &maxbytes))
1016                 return -1;
1017         if(maxbytes && len > maxbytes)
1018                 len = maxbytes;
1019
1020         DEBUG4("(WRITE to fd %d offset %llu len %u), ", fhandle, foffset, len);
1021
1022         myseek(fhandle, foffset);
1023         retval = write(fhandle, buf, len);
1024         if(client->server->flags & F_SYNC) {
1025                 fsync(fhandle);
1026         }
1027         return retval;
1028 }
1029
1030 /**
1031  * Call rawexpwrite repeatedly until all data has been written.
1032  * @return 0 on success, nonzero on failure
1033  **/
1034 int rawexpwrite_fully(off_t a, char *buf, size_t len, CLIENT *client) {
1035         ssize_t ret=0;
1036
1037         while(len > 0 && (ret=rawexpwrite(a, buf, len, client)) > 0 ) {
1038                 a += ret;
1039                 buf += ret;
1040                 len -= ret;
1041         }
1042         return (ret < 0 || len != 0);
1043 }
1044
1045 /**
1046  * Read an amount of bytes at a given offset from the right file. This
1047  * abstracts the read-side of the multiple files option.
1048  *
1049  * @param a The offset where the read should start
1050  * @param buf A buffer to read into
1051  * @param len The size of buf
1052  * @param client The client we're serving for
1053  * @return The number of bytes actually read, or -1 in case of an
1054  * error.
1055  **/
1056 ssize_t rawexpread(off_t a, char *buf, size_t len, CLIENT *client) {
1057         int fhandle;
1058         off_t foffset;
1059         size_t maxbytes;
1060
1061         if(get_filepos(client->export, a, &fhandle, &foffset, &maxbytes))
1062                 return -1;
1063         if(maxbytes && len > maxbytes)
1064                 len = maxbytes;
1065
1066         DEBUG4("(READ from fd %d offset %llu len %u), ", fhandle, foffset, len);
1067
1068         myseek(fhandle, foffset);
1069         return read(fhandle, buf, len);
1070 }
1071
1072 /**
1073  * Call rawexpread repeatedly until all data has been read.
1074  * @return 0 on success, nonzero on failure
1075  **/
1076 int rawexpread_fully(off_t a, char *buf, size_t len, CLIENT *client) {
1077         ssize_t ret=0;
1078
1079         while(len > 0 && (ret=rawexpread(a, buf, len, client)) > 0 ) {
1080                 a += ret;
1081                 buf += ret;
1082                 len -= ret;
1083         }
1084         return (ret < 0 || len != 0);
1085 }
1086
1087 /**
1088  * Read an amount of bytes at a given offset from the right file. This
1089  * abstracts the read-side of the copyonwrite stuff, and calls
1090  * rawexpread() with the right parameters to do the actual work.
1091  * @param a The offset where the read should start
1092  * @param buf A buffer to read into
1093  * @param len The size of buf
1094  * @param client The client we're going to read for
1095  * @return 0 on success, nonzero on failure
1096  **/
1097 int expread(off_t a, char *buf, size_t len, CLIENT *client) {
1098         off_t rdlen, offset;
1099         off_t mapcnt, mapl, maph, pagestart;
1100
1101         if (!(client->server->flags & F_COPYONWRITE))
1102                 return(rawexpread_fully(a, buf, len, client));
1103         DEBUG3("Asked to read %d bytes at %llu.\n", len, (unsigned long long)a);
1104
1105         mapl=a/DIFFPAGESIZE; maph=(a+len-1)/DIFFPAGESIZE;
1106
1107         for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
1108                 pagestart=mapcnt*DIFFPAGESIZE;
1109                 offset=a-pagestart;
1110                 rdlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
1111                         len : (size_t)DIFFPAGESIZE-offset;
1112                 if (client->difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
1113                         DEBUG3("Page %llu is at %lu\n", (unsigned long long)mapcnt,
1114                                (unsigned long)(client->difmap[mapcnt]));
1115                         myseek(client->difffile, client->difmap[mapcnt]*DIFFPAGESIZE+offset);
1116                         if (read(client->difffile, buf, rdlen) != rdlen) return -1;
1117                 } else { /* the block is not there */
1118                         DEBUG2("Page %llu is not here, we read the original one\n",
1119                                (unsigned long long)mapcnt);
1120                         if(rawexpread_fully(a, buf, rdlen, client)) return -1;
1121                 }
1122                 len-=rdlen; a+=rdlen; buf+=rdlen;
1123         }
1124         return 0;
1125 }
1126
1127 /**
1128  * Write an amount of bytes at a given offset to the right file. This
1129  * abstracts the write-side of the copyonwrite option, and calls
1130  * rawexpwrite() with the right parameters to do the actual work.
1131  *
1132  * @param a The offset where the write should start
1133  * @param buf The buffer to write from
1134  * @param len The length of buf
1135  * @param client The client we're going to write for.
1136  * @return 0 on success, nonzero on failure
1137  **/
1138 int expwrite(off_t a, char *buf, size_t len, CLIENT *client) {
1139         char pagebuf[DIFFPAGESIZE];
1140         off_t mapcnt,mapl,maph;
1141         off_t wrlen,rdlen; 
1142         off_t pagestart;
1143         off_t offset;
1144
1145         if (!(client->server->flags & F_COPYONWRITE))
1146                 return(rawexpwrite_fully(a, buf, len, client)); 
1147         DEBUG3("Asked to write %d bytes at %llu.\n", len, (unsigned long long)a);
1148
1149         mapl=a/DIFFPAGESIZE ; maph=(a+len-1)/DIFFPAGESIZE ;
1150
1151         for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
1152                 pagestart=mapcnt*DIFFPAGESIZE ;
1153                 offset=a-pagestart ;
1154                 wrlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
1155                         len : (size_t)DIFFPAGESIZE-offset;
1156
1157                 if (client->difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
1158                         DEBUG3("Page %llu is at %lu\n", (unsigned long long)mapcnt,
1159                                (unsigned long)(client->difmap[mapcnt])) ;
1160                         myseek(client->difffile,
1161                                         client->difmap[mapcnt]*DIFFPAGESIZE+offset);
1162                         if (write(client->difffile, buf, wrlen) != wrlen) return -1 ;
1163                 } else { /* the block is not there */
1164                         myseek(client->difffile,client->difffilelen*DIFFPAGESIZE) ;
1165                         client->difmap[mapcnt]=(client->server->flags&F_SPARSE)?mapcnt:client->difffilelen++;
1166                         DEBUG3("Page %llu is not here, we put it at %lu\n",
1167                                (unsigned long long)mapcnt,
1168                                (unsigned long)(client->difmap[mapcnt]));
1169                         rdlen=DIFFPAGESIZE ;
1170                         if (rawexpread_fully(pagestart, pagebuf, rdlen, client))
1171                                 return -1;
1172                         memcpy(pagebuf+offset,buf,wrlen) ;
1173                         if (write(client->difffile, pagebuf, DIFFPAGESIZE) !=
1174                                         DIFFPAGESIZE)
1175                                 return -1;
1176                 }                                                   
1177                 len-=wrlen ; a+=wrlen ; buf+=wrlen ;
1178         }
1179         return 0;
1180 }
1181
1182 /**
1183  * Do the initial negotiation.
1184  *
1185  * @param client The client we're negotiating with.
1186  **/
1187 void negotiate(CLIENT *client) {
1188         char zeros[128];
1189         u64 size_host;
1190         u32 flags = NBD_FLAG_HAS_FLAGS;
1191
1192         memset(zeros, '\0', sizeof(zeros));
1193         if (write(client->net, INIT_PASSWD, 8) < 0)
1194                 err("Negotiation failed: %m");
1195         cliserv_magic = htonll(cliserv_magic);
1196         if (write(client->net, &cliserv_magic, sizeof(cliserv_magic)) < 0)
1197                 err("Negotiation failed: %m");
1198         size_host = htonll((u64)(client->exportsize));
1199         if (write(client->net, &size_host, 8) < 0)
1200                 err("Negotiation failed: %m");
1201         if (client->server->flags & F_READONLY)
1202                 flags |= NBD_FLAG_READ_ONLY;
1203         flags = htonl(flags);
1204         if (write(client->net, &flags, 4) < 0)
1205                 err("Negotiation failed: %m");
1206         if (write(client->net, zeros, 124) < 0)
1207                 err("Negotiation failed: %m");
1208 }
1209
1210 /** sending macro. */
1211 #define SEND(net,reply) writeit( net, &reply, sizeof( reply ));
1212 /** error macro. */
1213 #define ERROR(client,reply,errcode) { reply.error = htonl(errcode); SEND(client->net,reply); reply.error = 0; }
1214 /**
1215  * Serve a file to a single client.
1216  *
1217  * @todo This beast needs to be split up in many tiny little manageable
1218  * pieces. Preferably with a chainsaw.
1219  *
1220  * @param client The client we're going to serve to.
1221  * @return when the client disconnects
1222  **/
1223 int mainloop(CLIENT *client) {
1224         struct nbd_request request;
1225         struct nbd_reply reply;
1226         gboolean go_on=TRUE;
1227 #ifdef DODBG
1228         int i = 0;
1229 #endif
1230         negotiate(client);
1231         DEBUG("Entering request loop!\n");
1232         reply.magic = htonl(NBD_REPLY_MAGIC);
1233         reply.error = 0;
1234         while (go_on) {
1235                 char buf[BUFSIZE];
1236                 size_t len;
1237 #ifdef DODBG
1238                 i++;
1239                 printf("%d: ", i);
1240 #endif
1241                 readit(client->net, &request, sizeof(request));
1242                 request.from = ntohll(request.from);
1243                 request.type = ntohl(request.type);
1244
1245                 if (request.type==NBD_CMD_DISC) {
1246                         msg2(LOG_INFO, "Disconnect request received.");
1247                         if (client->server->flags & F_COPYONWRITE) { 
1248                                 if (client->difmap) g_free(client->difmap) ;
1249                                 close(client->difffile);
1250                                 unlink(client->difffilename);
1251                                 free(client->difffilename);
1252                         }
1253                         go_on=FALSE;
1254                         continue;
1255                 }
1256
1257                 len = ntohl(request.len);
1258
1259                 if (request.magic != htonl(NBD_REQUEST_MAGIC))
1260                         err("Not enough magic.");
1261                 if (len > BUFSIZE + sizeof(struct nbd_reply))
1262                         err("Request too big!");
1263 #ifdef DODBG
1264                 printf("%s from %llu (%llu) len %d, ", request.type ? "WRITE" :
1265                                 "READ", (unsigned long long)request.from,
1266                                 (unsigned long long)request.from / 512, len);
1267 #endif
1268                 memcpy(reply.handle, request.handle, sizeof(reply.handle));
1269                 if ((request.from + len) > (OFFT_MAX)) {
1270                         DEBUG("[Number too large!]");
1271                         ERROR(client, reply, EINVAL);
1272                         continue;
1273                 }
1274
1275                 if (((ssize_t)((off_t)request.from + len) > client->exportsize)) {
1276                         DEBUG("[RANGE!]");
1277                         ERROR(client, reply, EINVAL);
1278                         continue;
1279                 }
1280
1281                 if (request.type==NBD_CMD_WRITE) {
1282                         DEBUG("wr: net->buf, ");
1283                         readit(client->net, buf, len);
1284                         DEBUG("buf->exp, ");
1285                         if ((client->server->flags & F_READONLY) ||
1286                             (client->server->flags & F_AUTOREADONLY)) {
1287                                 DEBUG("[WRITE to READONLY!]");
1288                                 ERROR(client, reply, EPERM);
1289                                 continue;
1290                         }
1291                         if (expwrite(request.from, buf, len, client)) {
1292                                 DEBUG("Write failed: %m" );
1293                                 ERROR(client, reply, errno);
1294                                 continue;
1295                         }
1296                         SEND(client->net, reply);
1297                         DEBUG("OK!\n");
1298                         continue;
1299                 }
1300                 /* READ */
1301
1302                 DEBUG("exp->buf, ");
1303                 if (expread(request.from, buf + sizeof(struct nbd_reply), len, client)) {
1304                         DEBUG("Read failed: %m");
1305                         ERROR(client, reply, errno);
1306                         continue;
1307                 }
1308
1309                 DEBUG("buf->net, ");
1310                 memcpy(buf, &reply, sizeof(struct nbd_reply));
1311                 writeit(client->net, buf, len + sizeof(struct nbd_reply));
1312                 DEBUG("OK!\n");
1313         }
1314         return 0;
1315 }
1316
1317 /**
1318  * Set up client export array, which is an array of FILE_INFO.
1319  * Also, split a single exportfile into multiple ones, if that was asked.
1320  * @param client information on the client which we want to setup export for
1321  **/
1322 void setupexport(CLIENT* client) {
1323         int i;
1324         off_t laststartoff = 0, lastsize = 0;
1325         int multifile = (client->server->flags & F_MULTIFILE);
1326
1327         client->export = g_array_new(TRUE, TRUE, sizeof(FILE_INFO));
1328
1329         /* If multi-file, open as many files as we can.
1330          * If not, open exactly one file.
1331          * Calculate file sizes as we go to get total size. */
1332         for(i=0; ; i++) {
1333                 FILE_INFO fi;
1334                 gchar *tmpname;
1335                 gchar* error_string;
1336                 mode_t mode = (client->server->flags & F_READONLY) ? O_RDONLY : O_RDWR;
1337
1338                 if(multifile) {
1339                         tmpname=g_strdup_printf("%s.%d", client->exportname, i);
1340                 } else {
1341                         tmpname=g_strdup(client->exportname);
1342                 }
1343                 DEBUG2( "Opening %s\n", tmpname );
1344                 fi.fhandle = open(tmpname, mode);
1345                 if(fi.fhandle == -1 && mode == O_RDWR) {
1346                         /* Try again because maybe media was read-only */
1347                         fi.fhandle = open(tmpname, O_RDONLY);
1348                         if(fi.fhandle != -1) {
1349                                 /* Opening the base file in copyonwrite mode is
1350                                  * okay */
1351                                 if(!(client->server->flags & F_COPYONWRITE)) {
1352                                         client->server->flags |= F_AUTOREADONLY;
1353                                         client->server->flags |= F_READONLY;
1354                                 }
1355                         }
1356                 }
1357                 if(fi.fhandle == -1) {
1358                         if(multifile && i>0)
1359                                 break;
1360                         error_string=g_strdup_printf(
1361                                 "Could not open exported file %s: %%m",
1362                                 tmpname);
1363                         err(error_string);
1364                 }
1365                 fi.startoff = laststartoff + lastsize;
1366                 g_array_append_val(client->export, fi);
1367                 g_free(tmpname);
1368
1369                 /* Starting offset and size of this file will be used to
1370                  * calculate starting offset of next file */
1371                 laststartoff = fi.startoff;
1372                 lastsize = size_autodetect(fi.fhandle);
1373
1374                 if(!multifile)
1375                         break;
1376         }
1377
1378         /* Set export size to total calculated size */
1379         client->exportsize = laststartoff + lastsize;
1380
1381         /* Export size may be overridden */
1382         if(client->server->expected_size) {
1383                 /* desired size must be <= total calculated size */
1384                 if(client->server->expected_size > client->exportsize) {
1385                         err("Size of exported file is too big\n");
1386                 }
1387
1388                 client->exportsize = client->server->expected_size;
1389         }
1390
1391         msg3(LOG_INFO, "Size of exported file/device is %llu", (unsigned long long)client->exportsize);
1392         if(multifile) {
1393                 msg3(LOG_INFO, "Total number of files: %d", i);
1394         }
1395 }
1396
1397 int copyonwrite_prepare(CLIENT* client) {
1398         off_t i;
1399         if ((client->difffilename = malloc(1024))==NULL)
1400                 err("Failed to allocate string for diff file name");
1401         snprintf(client->difffilename, 1024, "%s-%s-%d.diff",client->exportname,client->clientname,
1402                 (int)getpid()) ;
1403         client->difffilename[1023]='\0';
1404         msg3(LOG_INFO,"About to create map and diff file %s",client->difffilename) ;
1405         client->difffile=open(client->difffilename,O_RDWR | O_CREAT | O_TRUNC,0600) ;
1406         if (client->difffile<0) err("Could not create diff file (%m)") ;
1407         if ((client->difmap=calloc(client->exportsize/DIFFPAGESIZE,sizeof(u32)))==NULL)
1408                 err("Could not allocate memory") ;
1409         for (i=0;i<client->exportsize/DIFFPAGESIZE;i++) client->difmap[i]=(u32)-1 ;
1410
1411         return 0;
1412 }
1413
1414 /**
1415  * Run a command. This is used for the ``prerun'' and ``postrun'' config file
1416  * options
1417  *
1418  * @param command the command to be ran. Read from the config file
1419  * @param file the file name we're about to export
1420  **/
1421 int do_run(gchar* command, gchar* file) {
1422         gchar* cmd;
1423         int retval=0;
1424
1425         if(command && *command) {
1426                 cmd = g_strdup_printf(command, file);
1427                 retval=system(cmd);
1428                 g_free(cmd);
1429         }
1430         return retval;
1431 }
1432
1433 /**
1434  * Serve a connection. 
1435  *
1436  * @todo allow for multithreading, perhaps use libevent. Not just yet, though;
1437  * follow the road map.
1438  *
1439  * @param client a connected client
1440  **/
1441 void serveconnection(CLIENT *client) {
1442         if(do_run(client->server->prerun, client->exportname)) {
1443                 exit(EXIT_FAILURE);
1444         }
1445         setupexport(client);
1446
1447         if (client->server->flags & F_COPYONWRITE) {
1448                 copyonwrite_prepare(client);
1449         }
1450
1451         setmysockopt(client->net);
1452
1453         mainloop(client);
1454         do_run(client->server->postrun, client->exportname);
1455 }
1456
1457 /**
1458  * Find the name of the file we have to serve. This will use g_strdup_printf
1459  * to put the IP address of the client inside a filename containing
1460  * "%s" (in the form as specified by the "virtstyle" option). That name
1461  * is then written to client->exportname.
1462  *
1463  * @param net A socket connected to an nbd client
1464  * @param client information about the client. The IP address in human-readable
1465  * format will be written to a new char* buffer, the address of which will be
1466  * stored in client->clientname.
1467  **/
1468 void set_peername(int net, CLIENT *client) {
1469         struct sockaddr_storage addrin;
1470         struct sockaddr_storage netaddr;
1471         struct sockaddr_in  *netaddr4 = NULL;
1472         struct sockaddr_in6 *netaddr6 = NULL;
1473         size_t addrinlen = sizeof( addrin );
1474         struct addrinfo hints;
1475         struct addrinfo *ai = NULL;
1476         char peername[NI_MAXHOST];
1477         char netname[NI_MAXHOST];
1478         char *tmp = NULL;
1479         int i;
1480         int e;
1481         int shift;
1482
1483         if (getpeername(net, (struct sockaddr *) &addrin, (socklen_t *)&addrinlen) < 0)
1484                 err("getsockname failed: %m");
1485
1486         getnameinfo((struct sockaddr *)&addrin, (socklen_t)addrinlen,
1487                 peername, sizeof (peername), NULL, 0, NI_NUMERICHOST);
1488
1489         memset(&hints, '\0', sizeof (hints));
1490         hints.ai_flags = AI_ADDRCONFIG;
1491         e = getaddrinfo(peername, NULL, &hints, &ai);
1492
1493         if(e != 0) {
1494                 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
1495                 freeaddrinfo(ai);
1496                 return;
1497         }
1498
1499         switch(client->server->virtstyle) {
1500                 case VIRT_NONE:
1501                         client->exportname=g_strdup(client->server->exportname);
1502                         break;
1503                 case VIRT_IPHASH:
1504                         for(i=0;i<strlen(peername);i++) {
1505                                 if(peername[i]=='.') {
1506                                         peername[i]='/';
1507                                 }
1508                         }
1509                 case VIRT_IPLIT:
1510                         client->exportname=g_strdup_printf(client->server->exportname, peername);
1511                         break;
1512                 case VIRT_CIDR:
1513                         memcpy(&netaddr, &addrin, addrinlen);
1514                         if(ai->ai_family == AF_INET) {
1515                                 netaddr4 = (struct sockaddr_in *)&netaddr;
1516                                 (netaddr4->sin_addr).s_addr>>=32-(client->server->cidrlen);
1517                                 (netaddr4->sin_addr).s_addr<<=32-(client->server->cidrlen);
1518
1519                                 getnameinfo((struct sockaddr *) netaddr4, (socklen_t) addrinlen,
1520                                                         netname, sizeof (netname), NULL, 0, NI_NUMERICHOST);
1521                                 tmp=g_strdup_printf("%s/%s", netname, peername);
1522                         }else if(ai->ai_family == AF_INET6) {
1523                                 netaddr6 = (struct sockaddr_in6 *)&netaddr;
1524
1525                                 shift = 128-(client->server->cidrlen);
1526                                 i = 3;
1527                                 while(shift >= 32) {
1528                                         ((netaddr6->sin6_addr).s6_addr32[i])=0;
1529                                         shift-=32;
1530                                         i--;
1531                                 }
1532                                 (netaddr6->sin6_addr).s6_addr32[i]>>=shift;
1533                                 (netaddr6->sin6_addr).s6_addr32[i]<<=shift;
1534
1535                                 getnameinfo((struct sockaddr *)netaddr6, (socklen_t)addrinlen,
1536                                             netname, sizeof(netname), NULL, 0, NI_NUMERICHOST);
1537                                 tmp=g_strdup_printf("%s/%s", netname, peername);
1538                         }
1539
1540                         if(tmp != NULL)
1541                           client->exportname=g_strdup_printf(client->server->exportname, tmp);
1542
1543                         break;
1544         }
1545
1546         freeaddrinfo(ai);
1547         msg4(LOG_INFO, "connect from %s, assigned file is %s", 
1548              peername, client->exportname);
1549         client->clientname=g_strdup(peername);
1550 }
1551
1552 /**
1553  * Destroy a pid_t*
1554  * @param data a pointer to pid_t which should be freed
1555  **/
1556 void destroy_pid_t(gpointer data) {
1557         g_free(data);
1558 }
1559
1560 /**
1561  * Loop through the available servers, and serve them. Never returns.
1562  **/
1563 int serveloop(GArray* servers) {
1564         struct sockaddr_storage addrin;
1565         socklen_t addrinlen=sizeof(addrin);
1566         SERVER *serve;
1567         int i;
1568         int max;
1569         int sock;
1570         fd_set mset;
1571         fd_set rset;
1572
1573         /* 
1574          * Set up the master fd_set. The set of descriptors we need
1575          * to select() for never changes anyway and it buys us a *lot*
1576          * of time to only build this once. However, if we ever choose
1577          * to not fork() for clients anymore, we may have to revisit
1578          * this.
1579          */
1580         max=0;
1581         FD_ZERO(&mset);
1582         for(i=0;i<servers->len;i++) {
1583                 sock=(g_array_index(servers, SERVER, i)).socket;
1584                 FD_SET(sock, &mset);
1585                 max=sock>max?sock:max;
1586         }
1587         for(;;) {
1588                 CLIENT *client;
1589                 int net;
1590                 pid_t *pid;
1591
1592                 memcpy(&rset, &mset, sizeof(fd_set));
1593                 if(select(max+1, &rset, NULL, NULL, NULL)>0) {
1594                         DEBUG("accept, ");
1595                         for(i=0;i<servers->len;i++) {
1596                                 serve=&(g_array_index(servers, SERVER, i));
1597                                 if(FD_ISSET(serve->socket, &rset)) {
1598                                         int sock_flags;
1599                                         if ((net=accept(serve->socket, (struct sockaddr *) &addrin, &addrinlen)) < 0)
1600                                                 err("accept: %m");
1601
1602                                         if((sock_flags = fcntl(net, F_GETFL, 0))==-1) {
1603                                                 err("fcntl F_GETFL");
1604                                         }
1605                                         if(fcntl(net, F_SETFL, sock_flags &~O_NONBLOCK)==-1) {
1606                                                 err("fcntl F_SETFL ~O_NONBLOCK");
1607                                         }
1608                                         client = g_malloc(sizeof(CLIENT));
1609                                         client->server=serve;
1610                                         client->exportsize=OFFT_MAX;
1611                                         client->net=net;
1612                                         set_peername(net, client);
1613                                         if (!authorized_client(client)) {
1614                                                 msg2(LOG_INFO,"Unauthorized client") ;
1615                                                 close(net);
1616                                                 continue;
1617                                         }
1618                                         msg2(LOG_INFO,"Authorized client") ;
1619                                         pid=g_malloc(sizeof(pid_t));
1620 #ifndef NOFORK
1621                                         if ((*pid=fork())<0) {
1622                                                 msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ;
1623                                                 close(net);
1624                                                 continue;
1625                                         }
1626                                         if (*pid>0) { /* parent */
1627                                                 close(net);
1628                                                 g_hash_table_insert(children, pid, pid);
1629                                                 continue;
1630                                         }
1631                                         /* child */
1632                                         g_hash_table_destroy(children);
1633                                         for(i=0;i<servers->len;i++) {
1634                                                 serve=&g_array_index(servers, SERVER, i);
1635                                                 close(serve->socket);
1636                                         }
1637                                         /* FALSE does not free the
1638                                         actual data. This is required,
1639                                         because the client has a
1640                                         direct reference into that
1641                                         data, and otherwise we get a
1642                                         segfault... */
1643                                         g_array_free(servers, FALSE);
1644 #endif // NOFORK
1645                                         msg2(LOG_INFO,"Starting to serve");
1646                                         serveconnection(client);
1647                                         exit(EXIT_SUCCESS);
1648                                 }
1649                         }
1650                 }
1651         }
1652 }
1653
1654 /**
1655  * Connect a server's socket.
1656  *
1657  * @param serve the server we want to connect.
1658  **/
1659 void setup_serve(SERVER *serve) {
1660         struct sockaddr_storage addrin;
1661         struct addrinfo hints;
1662         struct addrinfo *ai = NULL;
1663         struct sigaction sa;
1664         int addrinlen = sizeof(addrin);
1665         int sock_flags;
1666 #ifndef sun
1667         int yes=1;
1668 #else
1669         char yes='1';
1670 #endif /* sun */
1671         gchar *port = NULL;
1672         int e;
1673
1674         memset(&hints,'\0',sizeof(hints));
1675         hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG | AI_NUMERICSERV;
1676         hints.ai_socktype = SOCK_STREAM;
1677         hints.ai_family = serve->socket_family;
1678
1679         port = g_strdup_printf ("%d", serve->port);
1680         if (port == NULL)
1681                 return;
1682
1683         e = getaddrinfo(serve->listenaddr,port,&hints,&ai);
1684
1685         g_free(port);
1686
1687         if(e != 0) {
1688                 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
1689                 serve->socket = -1;
1690                 freeaddrinfo(ai);
1691                 exit(EXIT_FAILURE);
1692         }
1693
1694         if(serve->socket_family == AF_UNSPEC)
1695                 serve->socket_family = ai->ai_family;
1696
1697 #ifdef WITH_SDP
1698         if ((serve->flags) && F_SDP) {
1699                 if (ai->ai_family == AF_INET)
1700                         ai->ai_family = AF_INET_SDP;
1701                 else (ai->ai_family == AF_INET6)
1702                         ai->ai_family = AF_INET6_SDP;
1703         }
1704 #endif
1705         if ((serve->socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0)
1706                 err("socket: %m");
1707
1708         /* lose the pesky "Address already in use" error message */
1709         if (setsockopt(serve->socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
1710                 err("setsockopt SO_REUSEADDR");
1711         }
1712         if (setsockopt(serve->socket,SOL_SOCKET,SO_KEEPALIVE,&yes,sizeof(int)) == -1) {
1713                 err("setsockopt SO_KEEPALIVE");
1714         }
1715
1716         /* make the listening socket non-blocking */
1717         if ((sock_flags = fcntl(serve->socket, F_GETFL, 0)) == -1) {
1718                 err("fcntl F_GETFL");
1719         }
1720         if (fcntl(serve->socket, F_SETFL, sock_flags | O_NONBLOCK) == -1) {
1721                 err("fcntl F_SETFL O_NONBLOCK");
1722         }
1723
1724         DEBUG("Waiting for connections... bind, ");
1725         e = bind(serve->socket, ai->ai_addr, ai->ai_addrlen);
1726         if (e != 0 && errno != EADDRINUSE)
1727                 err("bind: %m");
1728         DEBUG("listen, ");
1729         if (listen(serve->socket, 1) < 0)
1730                 err("listen: %m");
1731
1732         freeaddrinfo (ai);
1733
1734         sa.sa_handler = sigchld_handler;
1735         sigemptyset(&sa.sa_mask);
1736         sa.sa_flags = SA_RESTART;
1737         if(sigaction(SIGCHLD, &sa, NULL) == -1)
1738                 err("sigaction: %m");
1739         sa.sa_handler = sigterm_handler;
1740         sigemptyset(&sa.sa_mask);
1741         sa.sa_flags = SA_RESTART;
1742         if(sigaction(SIGTERM, &sa, NULL) == -1)
1743                 err("sigaction: %m");
1744 }
1745
1746 /**
1747  * Connect our servers.
1748  **/
1749 void setup_servers(GArray* servers) {
1750         int i;
1751
1752         for(i=0;i<servers->len;i++) {
1753                 setup_serve(&(g_array_index(servers, SERVER, i)));
1754         }
1755         children=g_hash_table_new_full(g_int_hash, g_int_equal, NULL, destroy_pid_t);
1756 }
1757
1758 /**
1759  * Go daemon (unless we specified at compile time that we didn't want this)
1760  * @param serve the first server of our configuration. If its port is zero,
1761  *      then do not daemonize, because we're doing inetd then. This parameter
1762  *      is only used to create a PID file of the form
1763  *      /var/run/nbd-server.&lt;port&gt;.pid; it's not modified in any way.
1764  **/
1765 #if !defined(NODAEMON) && !defined(NOFORK)
1766 void daemonize(SERVER* serve) {
1767         FILE*pidf;
1768
1769         if(serve && !(serve->port)) {
1770                 return;
1771         }
1772         if(daemon(0,0)<0) {
1773                 err("daemon");
1774         }
1775         if(!*pidftemplate) {
1776                 if(serve) {
1777                         strncpy(pidftemplate, "/var/run/nbd-server.%d.pid", 255);
1778                 } else {
1779                         strncpy(pidftemplate, "/var/run/nbd-server.pid", 255);
1780                 }
1781         }
1782         snprintf(pidfname, 255, pidftemplate, serve ? serve->port : 0);
1783         pidf=fopen(pidfname, "w");
1784         if(pidf) {
1785                 fprintf(pidf,"%d\n", (int)getpid());
1786                 fclose(pidf);
1787         } else {
1788                 perror("fopen");
1789                 fprintf(stderr, "Not fatal; continuing");
1790         }
1791 }
1792 #else
1793 #define daemonize(serve)
1794 #endif /* !defined(NODAEMON) && !defined(NOFORK) */
1795
1796 /*
1797  * Everything beyond this point (in the file) is run in non-daemon mode.
1798  * The stuff above daemonize() isn't.
1799  */
1800
1801 void serve_err(SERVER* serve, const char* msg) G_GNUC_NORETURN;
1802
1803 void serve_err(SERVER* serve, const char* msg) {
1804         g_message("Export of %s on port %d failed:", serve->exportname,
1805                         serve->port);
1806         err(msg);
1807 }
1808
1809 /**
1810  * Set up user-ID and/or group-ID
1811  **/
1812 void dousers(void) {
1813         struct passwd *pw;
1814         struct group *gr;
1815         gchar* str;
1816         if(rungroup) {
1817                 gr=getgrnam(rungroup);
1818                 if(!gr) {
1819                         str = g_strdup_printf("Invalid group name: %s", rungroup);
1820                         err(str);
1821                 }
1822                 if(setgid(gr->gr_gid)<0) {
1823                         err("Could not set GID: %m"); 
1824                 }
1825         }
1826         if(runuser) {
1827                 pw=getpwnam(runuser);
1828                 if(!pw) {
1829                         str = g_strdup_printf("Invalid user name: %s", runuser);
1830                         err(str);
1831                 }
1832                 if(setuid(pw->pw_uid)<0) {
1833                         err("Could not set UID: %m");
1834                 }
1835         }
1836 }
1837
1838 #ifndef ISSERVER
1839 void glib_message_syslog_redirect(const gchar *log_domain,
1840                                   GLogLevelFlags log_level,
1841                                   const gchar *message,
1842                                   gpointer user_data)
1843 {
1844     int level=LOG_DEBUG;
1845     
1846     switch( log_level )
1847     {
1848       case G_LOG_FLAG_FATAL:
1849       case G_LOG_LEVEL_CRITICAL:
1850       case G_LOG_LEVEL_ERROR:    
1851         level=LOG_ERR; 
1852         break;
1853       case G_LOG_LEVEL_WARNING:
1854         level=LOG_WARNING;
1855         break;
1856       case G_LOG_LEVEL_MESSAGE:
1857       case G_LOG_LEVEL_INFO:
1858         level=LOG_INFO;
1859         break;
1860       case G_LOG_LEVEL_DEBUG:
1861         level=LOG_DEBUG;
1862       default:
1863         level=LOG_ERR;
1864     }
1865     syslog(level, message);
1866 }
1867 #endif
1868
1869 /**
1870  * Main entry point...
1871  **/
1872 int main(int argc, char *argv[]) {
1873         SERVER *serve;
1874         GArray *servers;
1875         GError *err=NULL;
1876
1877         if (sizeof( struct nbd_request )!=28) {
1878                 fprintf(stderr,"Bad size of structure. Alignment problems?\n");
1879                 exit(EXIT_FAILURE) ;
1880         }
1881
1882         memset(pidftemplate, '\0', 256);
1883
1884         logging();
1885         config_file_pos = g_strdup(CFILE);
1886         serve=cmdline(argc, argv);
1887         servers = parse_cfile(config_file_pos, &err);
1888         
1889         if(serve) {
1890                 serve->socket_family = AF_UNSPEC;
1891
1892                 append_serve(serve, servers);
1893      
1894                 if (!(serve->port)) {
1895                         CLIENT *client;
1896 #ifndef ISSERVER
1897                         /* You really should define ISSERVER if you're going to use
1898                          * inetd mode, but if you don't, closing stdout and stderr
1899                          * (which inetd had connected to the client socket) will let it
1900                          * work. */
1901                         close(1);
1902                         close(2);
1903                         open("/dev/null", O_WRONLY);
1904                         open("/dev/null", O_WRONLY);
1905                         g_log_set_default_handler( glib_message_syslog_redirect, NULL );
1906 #endif
1907                         client=g_malloc(sizeof(CLIENT));
1908                         client->server=serve;
1909                         client->net=0;
1910                         client->exportsize=OFFT_MAX;
1911                         set_peername(0,client);
1912                         serveconnection(client);
1913                         return 0;
1914                 }
1915         }
1916     
1917     if(!servers || !servers->len) {
1918                 g_warning("Could not parse config file: %s", 
1919                                 err ? err->message : "Unknown error");
1920         }
1921     
1922         if((!serve) && (!servers||!servers->len)) {
1923                 g_message("Nothing to do! Bye!");
1924                 exit(EXIT_FAILURE);
1925         }
1926         daemonize(serve);
1927         setup_servers(servers);
1928         dousers();
1929         serveloop(servers);
1930         return 0 ;
1931 }