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