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