Network Block Device  @PACKAGE_VERSION@
nbd-server.c
Go to the documentation of this file.
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 <assert.h>
63 #include <sys/types.h>
64 #include <sys/socket.h>
65 #include <sys/stat.h>
66 #include <sys/select.h>
67 #include <sys/wait.h>
68 #ifdef HAVE_SYS_IOCTL_H
69 #include <sys/ioctl.h>
70 #endif
71 #include <sys/param.h>
72 #ifdef HAVE_SYS_MOUNT_H
73 #include <sys/mount.h>
74 #endif
75 #include <signal.h>
76 #include <errno.h>
77 #include <netinet/tcp.h>
78 #include <netinet/in.h>
79 #include <netdb.h>
80 #include <syslog.h>
81 #include <unistd.h>
82 #include <stdbool.h>
83 #include <stdio.h>
84 #include <stdlib.h>
85 #include <string.h>
86 #include <fcntl.h>
87 #if HAVE_FALLOC_PH
88 #include <linux/falloc.h>
89 #endif
90 #include <arpa/inet.h>
91 #include <strings.h>
92 #include <dirent.h>
93 #include <unistd.h>
94 #include <getopt.h>
95 #include <pwd.h>
96 #include <grp.h>
97 #include <dirent.h>
98 
99 #include <glib.h>
100 
101 /* used in cliserv.h, so must come first */
102 #define MY_NAME "nbd_server"
103 #include "cliserv.h"
104 
105 #ifdef WITH_SDP
106 #include <sdp_inet.h>
107 #endif
108 
109 /** Default position of the config file */
110 #ifndef SYSCONFDIR
111 #define SYSCONFDIR "/etc"
112 #endif
113 #define CFILE SYSCONFDIR "/nbd-server/config"
114 
115 /** Where our config file actually is */
117 
118 /** What user we're running as */
119 gchar* runuser=NULL;
120 /** What group we're running as */
121 gchar* rungroup=NULL;
122 /** global flags */
124 
125 /* Whether we should avoid forking */
126 int dontfork = 0;
127 
128 /** Logging macros, now nothing goes to syslog unless you say ISSERVER */
129 #ifdef ISSERVER
130 #define msg2(a,b) syslog(a,b)
131 #define msg3(a,b,c) syslog(a,b,c)
132 #define msg4(a,b,c,d) syslog(a,b,c,d)
133 #else
134 #define msg2(a,b) g_message((char*)b)
135 #define msg3(a,b,c) g_message((char*)b,c)
136 #define msg4(a,b,c,d) g_message((char*)b,c,d)
137 #endif
138 
139 /* Debugging macros */
140 //#define DODBG
141 #ifdef DODBG
142 #define DEBUG(...) printf(__VA_ARGS__)
143 #else
144 #define DEBUG(...)
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 
159 /** Per-export flags: */
160 #define F_READONLY 1 /**< flag to tell us a file is readonly */
161 #define F_MULTIFILE 2 /**< flag to tell us a file is exported using -m */
162 #define F_COPYONWRITE 4 /**< flag to tell us a file is exported using
163  copyonwrite */
164 #define F_AUTOREADONLY 8 /**< flag to tell us a file is set to autoreadonly */
165 #define F_SPARSE 16 /**< flag to tell us copyronwrite should use a sparse file */
166 #define F_SDP 32 /**< flag to tell us the export should be done using the Socket Direct Protocol for RDMA */
167 #define F_SYNC 64 /**< Whether to fsync() after a write */
168 #define F_FLUSH 128 /**< Whether server wants FLUSH to be sent by the client */
169 #define F_FUA 256 /**< Whether server wants FUA to be sent by the client */
170 #define F_ROTATIONAL 512 /**< Whether server wants the client to implement the elevator algorithm */
171 #define F_TEMPORARY 1024 /**< Whether the backing file is temporary and should be created then unlinked */
172 #define F_TRIM 2048 /**< Whether server wants TRIM (discard) to be sent by the client */
173 #define F_FIXED 4096 /**< Client supports fixed new-style protocol (and can thus send us extra options */
174 
175 /** Global flags: */
176 #define F_OLDSTYLE 1 /**< Allow oldstyle (port-based) exports */
177 #define F_LIST 2 /**< Allow clients to list the exports on a server */
178 GHashTable *children;
179 char pidfname[256]; /**< name of our PID file */
180 char pidftemplate[256]; /**< template to be used for the filename of the PID file */
181 char default_authname[] = SYSCONFDIR "/nbd-server/allow"; /**< default name of allow file */
182 
183 #define NEG_INIT (1 << 0)
184 #define NEG_OLD (1 << 1)
185 #define NEG_MODERN (1 << 2)
186 
187 int modernsock=0; /**< Socket for the modern handler. Not used
188  if a client was only specified on the
189  command line; only port used if
190  oldstyle is set to false (and then the
191  command-line client isn't used, gna gna) */
192 char* modern_listen; /**< listenaddr value for modernsock */
193 char* modernport=NBD_DEFAULT_PORT; /**< Port number on which to listen for
194  new-style nbd-client connections */
195 
196 bool logged_oversized=false; /**< whether we logged oversized requests already */
197 
198 /**
199  * Types of virtuatlization
200  **/
201 typedef enum {
202  VIRT_NONE=0, /**< No virtualization */
203  VIRT_IPLIT, /**< Literal IP address as part of the filename */
204  VIRT_IPHASH, /**< Replacing all dots in an ip address by a / before
205  doing the same as in IPLIT */
206  VIRT_CIDR, /**< Every subnet in its own directory */
207 } VIRT_STYLE;
208 
209 /**
210  * Variables associated with a server.
211  **/
212 typedef struct {
213  gchar* exportname; /**< (unprocessed) filename of the file we're exporting */
214  off_t expected_size; /**< size of the exported file as it was told to
215  us through configuration */
216  gchar* listenaddr; /**< The IP address we're listening on */
217  unsigned int port; /**< port we're exporting this file at */
218  char* authname; /**< filename of the authorization file */
219  int flags; /**< flags associated with this exported file */
220  int socket; /**< The socket of this server. */
221  int socket_family; /**< family of the socket */
222  VIRT_STYLE virtstyle;/**< The style of virtualization, if any */
223  uint8_t cidrlen; /**< The length of the mask when we use
224  CIDR-style virtualization */
225  gchar* prerun; /**< command to be ran after connecting a client,
226  but before starting to serve */
227  gchar* postrun; /**< command that will be ran after the client
228  disconnects */
229  gchar* servename; /**< name of the export as selected by nbd-client */
230  int max_connections; /**< maximum number of opened connections */
231  gchar* transactionlog;/**< filename for transaction log */
232 } SERVER;
233 
234 /**
235  * Variables associated with a client socket.
236  **/
237 typedef struct {
238  int fhandle; /**< file descriptor */
239  off_t startoff; /**< starting offset of this file */
240 } FILE_INFO;
241 
242 typedef struct {
243  off_t exportsize; /**< size of the file we're exporting */
244  char *clientname; /**< peer */
245  char *exportname; /**< (processed) filename of the file we're exporting */
246  GArray *export; /**< array of FILE_INFO of exported files;
247  array size is always 1 unless we're
248  doing the multiple file option */
249  int net; /**< The actual client socket */
250  SERVER *server; /**< The server this client is getting data from */
251  char* difffilename; /**< filename of the copy-on-write file, if any */
252  int difffile; /**< filedescriptor of copyonwrite file. @todo
253  shouldn't this be an array too? (cfr export) Or
254  make -m and -c mutually exclusive */
255  u32 difffilelen; /**< number of pages in difffile */
256  u32 *difmap; /**< see comment on the global difmap for this one */
257  gboolean modern; /**< client was negotiated using modern negotiation protocol */
258  int transactionlogfd;/**< fd for transaction log */
259  int clientfeats; /**< Features supported by this client */
260 } CLIENT;
261 
262 /**
263  * Type of configuration file values
264  **/
265 typedef enum {
266  PARAM_INT, /**< This parameter is an integer */
267  PARAM_INT64, /**< This parameter is an integer */
268  PARAM_STRING, /**< This parameter is a string */
269  PARAM_BOOL, /**< This parameter is a boolean */
270 } PARAM_TYPE;
271 
272 /**
273  * Configuration file values
274  **/
275 typedef struct {
276  gchar *paramname; /**< Name of the parameter, as it appears in
277  the config file */
278  gboolean required; /**< Whether this is a required (as opposed to
279  optional) parameter */
280  PARAM_TYPE ptype; /**< Type of the parameter. */
281  gpointer target; /**< Pointer to where the data of this
282  parameter should be written. If ptype is
283  PARAM_BOOL, the data is or'ed rather than
284  overwritten. */
285  gint flagval; /**< Flag mask for this parameter in case ptype
286  is PARAM_BOOL. */
287 } PARAM;
288 
289 /**
290  * Translate a command name into human readable form
291  *
292  * @param command The command number (after applying NBD_CMD_MASK_COMMAND)
293  * @return pointer to the command name
294  **/
295 static inline const char * getcommandname(uint64_t command) {
296  switch (command) {
297  case NBD_CMD_READ:
298  return "NBD_CMD_READ";
299  case NBD_CMD_WRITE:
300  return "NBD_CMD_WRITE";
301  case NBD_CMD_DISC:
302  return "NBD_CMD_DISC";
303  case NBD_CMD_FLUSH:
304  return "NBD_CMD_FLUSH";
305  default:
306  break;
307  }
308  return "UNKNOWN";
309 }
310 
311 /**
312  * Check whether a client is allowed to connect. Works with an authorization
313  * file which contains one line per machine, no wildcards.
314  *
315  * @param opts The client who's trying to connect.
316  * @return 0 - authorization refused, 1 - OK
317  **/
319  const char *ERRMSG="Invalid entry '%s' in authfile '%s', so, refusing all connections.";
320  FILE *f ;
321  char line[LINELEN];
322  char *tmp;
323  struct in_addr addr;
324  struct in_addr client;
325  struct in_addr cltemp;
326  int len;
327 
328  if ((f=fopen(opts->server->authname,"r"))==NULL) {
329  msg4(LOG_INFO,"Can't open authorization file %s (%s).",
330  opts->server->authname,strerror(errno)) ;
331  return 1 ;
332  }
333 
334  inet_aton(opts->clientname, &client);
335  while (fgets(line,LINELEN,f)!=NULL) {
336  if((tmp=strchr(line, '/'))) {
337  if(strlen(line)<=tmp-line) {
338  msg4(LOG_CRIT, ERRMSG, line, opts->server->authname);
339  return 0;
340  }
341  *(tmp++)=0;
342  if(!inet_aton(line,&addr)) {
343  msg4(LOG_CRIT, ERRMSG, line, opts->server->authname);
344  return 0;
345  }
346  len=strtol(tmp, NULL, 0);
347  addr.s_addr>>=32-len;
348  addr.s_addr<<=32-len;
349  memcpy(&cltemp,&client,sizeof(client));
350  cltemp.s_addr>>=32-len;
351  cltemp.s_addr<<=32-len;
352  if(addr.s_addr == cltemp.s_addr) {
353  return 1;
354  }
355  }
356  if (strncmp(line,opts->clientname,strlen(opts->clientname))==0) {
357  fclose(f);
358  return 1;
359  }
360  }
361  fclose(f);
362  return 0;
363 }
364 
365 /**
366  * Read data from a file descriptor into a buffer
367  *
368  * @param f a file descriptor
369  * @param buf a buffer
370  * @param len the number of bytes to be read
371  **/
372 static inline void readit(int f, void *buf, size_t len) {
373  ssize_t res;
374  while (len > 0) {
375  DEBUG("*");
376  if ((res = read(f, buf, len)) <= 0) {
377  if(errno != EAGAIN) {
378  err("Read failed: %m");
379  }
380  } else {
381  len -= res;
382  buf += res;
383  }
384  }
385 }
386 
387 /**
388  * Consume data from an FD that we don't want
389  *
390  * @param f a file descriptor
391  * @param buf a buffer
392  * @param len the number of bytes to consume
393  * @param bufsiz the size of the buffer
394  **/
395 static inline void consume(int f, void * buf, size_t len, size_t bufsiz) {
396  size_t curlen;
397  while (len>0) {
398  curlen = (len>bufsiz)?bufsiz:len;
399  readit(f, buf, curlen);
400  len -= curlen;
401  }
402 }
403 
404 
405 /**
406  * Write data from a buffer into a filedescriptor
407  *
408  * @param f a file descriptor
409  * @param buf a buffer containing data
410  * @param len the number of bytes to be written
411  **/
412 static inline void writeit(int f, void *buf, size_t len) {
413  ssize_t res;
414  while (len > 0) {
415  DEBUG("+");
416  if ((res = write(f, buf, len)) <= 0)
417  err("Send failed: %m");
418  len -= res;
419  buf += res;
420  }
421 }
422 
423 /**
424  * Print out a message about how to use nbd-server. Split out to a separate
425  * function so that we can call it from multiple places
426  */
427 void usage() {
428  printf("This is nbd-server version " VERSION "\n");
429  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"
430  "\t-r|--read-only\t\tread only\n"
431  "\t-m|--multi-file\t\tmultiple file\n"
432  "\t-c|--copy-on-write\tcopy on write\n"
433  "\t-C|--config-file\tspecify an alternate configuration file\n"
434  "\t-l|--authorize-file\tfile with list of hosts that are allowed to\n\t\t\t\tconnect.\n"
435  "\t-p|--pid-file\t\tspecify a filename to write our PID to\n"
436  "\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"
437  "\t-M|--max-connections\tspecify the maximum number of opened connections\n\n"
438  "\tif port is set to 0, stdin is used (for running from inetd).\n"
439  "\tif file_to_export contains '%%s', it is substituted with the IP\n"
440  "\t\taddress of the machine trying to connect\n"
441  "\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");
442  printf("Using configuration file %s\n", CFILE);
443 }
444 
445 /* Dumps a config file section of the given SERVER*, and exits. */
446 void dump_section(SERVER* serve, gchar* section_header) {
447  printf("[%s]\n", section_header);
448  printf("\texportname = %s\n", serve->exportname);
449  printf("\tlistenaddr = %s\n", serve->listenaddr);
450  printf("\tport = %d\n", serve->port);
451  if(serve->flags & F_READONLY) {
452  printf("\treadonly = true\n");
453  }
454  if(serve->flags & F_MULTIFILE) {
455  printf("\tmultifile = true\n");
456  }
457  if(serve->flags & F_COPYONWRITE) {
458  printf("\tcopyonwrite = true\n");
459  }
460  if(serve->expected_size) {
461  printf("\tfilesize = %lld\n", (long long int)serve->expected_size);
462  }
463  if(serve->authname) {
464  printf("\tauthfile = %s\n", serve->authname);
465  }
466  exit(EXIT_SUCCESS);
467 }
468 
469 /**
470  * Parse the command line.
471  *
472  * @param argc the argc argument to main()
473  * @param argv the argv argument to main()
474  **/
475 SERVER* cmdline(int argc, char *argv[]) {
476  int i=0;
477  int nonspecial=0;
478  int c;
479  struct option long_options[] = {
480  {"read-only", no_argument, NULL, 'r'},
481  {"multi-file", no_argument, NULL, 'm'},
482  {"copy-on-write", no_argument, NULL, 'c'},
483  {"dont-fork", no_argument, NULL, 'd'},
484  {"authorize-file", required_argument, NULL, 'l'},
485  {"config-file", required_argument, NULL, 'C'},
486  {"pid-file", required_argument, NULL, 'p'},
487  {"output-config", required_argument, NULL, 'o'},
488  {"max-connection", required_argument, NULL, 'M'},
489  {0,0,0,0}
490  };
491  SERVER *serve;
492  off_t es;
493  size_t last;
494  char suffix;
495  gboolean do_output=FALSE;
496  gchar* section_header="";
497  gchar** addr_port;
498 
499  if(argc==1) {
500  return NULL;
501  }
502  serve=g_new0(SERVER, 1);
503  serve->authname = g_strdup(default_authname);
504  serve->virtstyle=VIRT_IPLIT;
505  while((c=getopt_long(argc, argv, "-C:cdl:mo:rp:M:", long_options, &i))>=0) {
506  switch (c) {
507  case 1:
508  /* non-option argument */
509  switch(nonspecial++) {
510  case 0:
511  if(strchr(optarg, ':') == strrchr(optarg, ':')) {
512  addr_port=g_strsplit(optarg, ":", 2);
513 
514  /* Check for "@" - maybe user using this separator
515  for IPv4 address */
516  if(!addr_port[1]) {
517  g_strfreev(addr_port);
518  addr_port=g_strsplit(optarg, "@", 2);
519  }
520  } else {
521  addr_port=g_strsplit(optarg, "@", 2);
522  }
523 
524  if(addr_port[1]) {
525  serve->port=strtol(addr_port[1], NULL, 0);
526  serve->listenaddr=g_strdup(addr_port[0]);
527  } else {
528  serve->listenaddr=NULL;
529  serve->port=strtol(addr_port[0], NULL, 0);
530  }
531  g_strfreev(addr_port);
532  break;
533  case 1:
534  serve->exportname = g_strdup(optarg);
535  if(serve->exportname[0] != '/') {
536  fprintf(stderr, "E: The to be exported file needs to be an absolute filename!\n");
537  exit(EXIT_FAILURE);
538  }
539  break;
540  case 2:
541  last=strlen(optarg)-1;
542  suffix=optarg[last];
543  if (suffix == 'k' || suffix == 'K' ||
544  suffix == 'm' || suffix == 'M')
545  optarg[last] = '\0';
546  es = (off_t)atoll(optarg);
547  switch (suffix) {
548  case 'm':
549  case 'M': es <<= 10;
550  case 'k':
551  case 'K': es <<= 10;
552  default : break;
553  }
554  serve->expected_size = es;
555  break;
556  }
557  break;
558  case 'r':
559  serve->flags |= F_READONLY;
560  break;
561  case 'm':
562  serve->flags |= F_MULTIFILE;
563  break;
564  case 'o':
565  do_output = TRUE;
566  section_header = g_strdup(optarg);
567  break;
568  case 'p':
569  strncpy(pidftemplate, optarg, 256);
570  break;
571  case 'c':
572  serve->flags |=F_COPYONWRITE;
573  break;
574  case 'd':
575  dontfork = 1;
576  break;
577  case 'C':
578  g_free(config_file_pos);
579  config_file_pos=g_strdup(optarg);
580  break;
581  case 'l':
582  g_free(serve->authname);
583  serve->authname=g_strdup(optarg);
584  break;
585  case 'M':
586  serve->max_connections = strtol(optarg, NULL, 0);
587  break;
588  default:
589  usage();
590  exit(EXIT_FAILURE);
591  break;
592  }
593  }
594  /* What's left: the port to export, the name of the to be exported
595  * file, and, optionally, the size of the file, in that order. */
596  if(nonspecial<2) {
597  g_free(serve);
598  serve=NULL;
599  } else {
601  }
602  if(do_output) {
603  if(!serve) {
604  g_critical("Need a complete configuration on the command line to output a config file section!");
605  exit(EXIT_FAILURE);
606  }
607  dump_section(serve, section_header);
608  }
609  return serve;
610 }
611 
612 /**
613  * Error codes for config file parsing
614  **/
615 typedef enum {
616  CFILE_NOTFOUND, /**< The configuration file is not found */
617  CFILE_MISSING_GENERIC, /**< The (required) group "generic" is missing */
618  CFILE_KEY_MISSING, /**< A (required) key is missing */
619  CFILE_VALUE_INVALID, /**< A value is syntactically invalid */
620  CFILE_VALUE_UNSUPPORTED,/**< A value is not supported in this build */
621  CFILE_PROGERR, /**< Programmer error */
622  CFILE_NO_EXPORTS, /**< A config file was specified that does not
623  define any exports */
624  CFILE_INCORRECT_PORT, /**< The reserved port was specified for an
625  old-style export. */
626  CFILE_DIR_UNKNOWN, /**< A directory requested does not exist*/
627  CFILE_READDIR_ERR, /**< Error occurred during readdir() */
628 } CFILE_ERRORS;
629 
630 /**
631  * Remove a SERVER from memory. Used from the hash table
632  **/
633 void remove_server(gpointer s) {
634  SERVER *server;
635 
636  server=(SERVER*)s;
637  g_free(server->exportname);
638  if(server->authname)
639  g_free(server->authname);
640  if(server->listenaddr)
641  g_free(server->listenaddr);
642  if(server->prerun)
643  g_free(server->prerun);
644  if(server->postrun)
645  g_free(server->postrun);
646  if(server->transactionlog)
647  g_free(server->transactionlog);
648  g_free(server);
649 }
650 
651 /**
652  * duplicate server
653  * @param s the old server we want to duplicate
654  * @return new duplicated server
655  **/
657  SERVER *serve = NULL;
658 
659  serve=g_new0(SERVER, 1);
660  if(serve == NULL)
661  return NULL;
662 
663  if(s->exportname)
664  serve->exportname = g_strdup(s->exportname);
665 
666  serve->expected_size = s->expected_size;
667 
668  if(s->listenaddr)
669  serve->listenaddr = g_strdup(s->listenaddr);
670 
671  serve->port = s->port;
672 
673  if(s->authname)
674  serve->authname = strdup(s->authname);
675 
676  serve->flags = s->flags;
677  serve->socket = s->socket;
678  serve->socket_family = s->socket_family;
679  serve->virtstyle = s->virtstyle;
680  serve->cidrlen = s->cidrlen;
681 
682  if(s->prerun)
683  serve->prerun = g_strdup(s->prerun);
684 
685  if(s->postrun)
686  serve->postrun = g_strdup(s->postrun);
687 
688  if(s->transactionlog)
689  serve->transactionlog = g_strdup(s->transactionlog);
690 
691  if(s->servename)
692  serve->servename = g_strdup(s->servename);
693 
694  serve->max_connections = s->max_connections;
695 
696  return serve;
697 }
698 
699 /**
700  * append new server to array
701  * @param s server
702  * @param a server array
703  * @return 0 success, -1 error
704  */
705 int append_serve(SERVER *s, GArray *a) {
706  SERVER *ns = NULL;
707  struct addrinfo hints;
708  struct addrinfo *ai = NULL;
709  struct addrinfo *rp = NULL;
710  char host[NI_MAXHOST];
711  gchar *port = NULL;
712  int e;
713  int ret;
714 
715  if(!s) {
716  err("Invalid parsing server");
717  return -1;
718  }
719 
720  port = g_strdup_printf("%d", s->port);
721 
722  memset(&hints,'\0',sizeof(hints));
723  hints.ai_family = AF_UNSPEC;
724  hints.ai_socktype = SOCK_STREAM;
725  hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
726  hints.ai_protocol = IPPROTO_TCP;
727 
728  e = getaddrinfo(s->listenaddr, port, &hints, &ai);
729 
730  if (port)
731  g_free(port);
732 
733  if(e == 0) {
734  for (rp = ai; rp != NULL; rp = rp->ai_next) {
735  e = getnameinfo(rp->ai_addr, rp->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
736 
737  if (e != 0) { // error
738  fprintf(stderr, "getnameinfo: %s\n", gai_strerror(e));
739  continue;
740  }
741 
742  // duplicate server and set listenaddr to resolved IP address
743  ns = dup_serve (s);
744  if (ns) {
745  ns->listenaddr = g_strdup(host);
746  ns->socket_family = rp->ai_family;
747  g_array_append_val(a, *ns);
748  free(ns);
749  ns = NULL;
750  }
751  }
752 
753  ret = 0;
754  } else {
755  fprintf(stderr, "getaddrinfo failed on listen host/address: %s (%s)\n", s->listenaddr ? s->listenaddr : "any", gai_strerror(e));
756  ret = -1;
757  }
758 
759  if (ai)
760  freeaddrinfo(ai);
761 
762  return ret;
763 }
764 
765 /* forward definition of parse_cfile */
766 GArray* parse_cfile(gchar* f, bool have_global, GError** e);
767 
768 /**
769  * Parse config file snippets in a directory. Uses readdir() and friends
770  * to find files and open them, then passes them on to parse_cfile
771  * with have_global set false
772  **/
773 GArray* do_cfile_dir(gchar* dir, GError** e) {
774  DIR* dirh = opendir(dir);
775  GQuark errdomain = g_quark_from_string("do_cfile_dir");
776  struct dirent* de;
777  gchar* fname;
778  GArray* retval = NULL;
779  GArray* tmp;
780  struct stat stbuf;
781 
782  if(!dir) {
783  g_set_error(e, errdomain, CFILE_DIR_UNKNOWN, "Invalid directory specified: %s", strerror(errno));
784  return NULL;
785  }
786  errno=0;
787  while((de = readdir(dirh))) {
788  int saved_errno=errno;
789  fname = g_build_filename(dir, de->d_name, NULL);
790  switch(de->d_type) {
791  case DT_UNKNOWN:
792  /* Filesystem doesn't return type of
793  * file through readdir. Run stat() on
794  * the file instead */
795  if(stat(fname, &stbuf)) {
796  perror("stat");
797  goto err_out;
798  }
799  if (!S_ISREG(stbuf.st_mode)) {
800  goto next;
801  }
802  case DT_REG:
803  /* Skip unless the name ends with '.conf' */
804  if(strcmp((de->d_name + strlen(de->d_name) - 5), ".conf")) {
805  continue;
806  }
807  tmp = parse_cfile(fname, FALSE, e);
808  errno=saved_errno;
809  if(*e) {
810  goto err_out;
811  }
812  if(!retval)
813  retval = g_array_new(FALSE, TRUE, sizeof(SERVER));
814  retval = g_array_append_vals(retval, tmp->data, tmp->len);
815  g_array_free(tmp, TRUE);
816  default:
817  break;
818  }
819  next:
820  g_free(fname);
821  }
822  if(errno) {
823  g_set_error(e, errdomain, CFILE_READDIR_ERR, "Error trying to read directory: %s", strerror(errno));
824  err_out:
825  if(retval)
826  g_array_free(retval, TRUE);
827  return NULL;
828  }
829  return retval;
830 }
831 
832 /**
833  * Parse the config file.
834  *
835  * @param f the name of the config file
836  * @param e a GError. @see CFILE_ERRORS for what error values this function can
837  * return.
838  * @return a Array of SERVER* pointers, If the config file is empty or does not
839  * exist, returns an empty GHashTable; if the config file contains an
840  * error, returns NULL, and e is set appropriately
841  **/
842 GArray* parse_cfile(gchar* f, bool have_global, GError** e) {
843  const char* DEFAULT_ERROR = "Could not parse %s in group %s: %s";
844  const char* MISSING_REQUIRED_ERROR = "Could not find required value %s in group %s: %s";
845  gchar* cfdir = NULL;
846  SERVER s;
847  gchar *virtstyle=NULL;
848  PARAM lp[] = {
849  { "exportname", TRUE, PARAM_STRING, &(s.exportname), 0 },
850  { "port", TRUE, PARAM_INT, &(s.port), 0 },
851  { "authfile", FALSE, PARAM_STRING, &(s.authname), 0 },
852  { "filesize", FALSE, PARAM_OFFT, &(s.expected_size), 0 },
853  { "virtstyle", FALSE, PARAM_STRING, &(virtstyle), 0 },
854  { "prerun", FALSE, PARAM_STRING, &(s.prerun), 0 },
855  { "postrun", FALSE, PARAM_STRING, &(s.postrun), 0 },
856  { "transactionlog", FALSE, PARAM_STRING, &(s.transactionlog), 0 },
857  { "readonly", FALSE, PARAM_BOOL, &(s.flags), F_READONLY },
858  { "multifile", FALSE, PARAM_BOOL, &(s.flags), F_MULTIFILE },
859  { "copyonwrite", FALSE, PARAM_BOOL, &(s.flags), F_COPYONWRITE },
860  { "sparse_cow", FALSE, PARAM_BOOL, &(s.flags), F_SPARSE },
861  { "sdp", FALSE, PARAM_BOOL, &(s.flags), F_SDP },
862  { "sync", FALSE, PARAM_BOOL, &(s.flags), F_SYNC },
863  { "flush", FALSE, PARAM_BOOL, &(s.flags), F_FLUSH },
864  { "fua", FALSE, PARAM_BOOL, &(s.flags), F_FUA },
865  { "rotational", FALSE, PARAM_BOOL, &(s.flags), F_ROTATIONAL },
866  { "temporary", FALSE, PARAM_BOOL, &(s.flags), F_TEMPORARY },
867  { "trim", FALSE, PARAM_BOOL, &(s.flags), F_TRIM },
868  { "listenaddr", FALSE, PARAM_STRING, &(s.listenaddr), 0 },
869  { "maxconnections", FALSE, PARAM_INT, &(s.max_connections), 0 },
870  };
871  const int lp_size=sizeof(lp)/sizeof(PARAM);
872  PARAM gp[] = {
873  { "user", FALSE, PARAM_STRING, &runuser, 0 },
874  { "group", FALSE, PARAM_STRING, &rungroup, 0 },
875  { "oldstyle", FALSE, PARAM_BOOL, &glob_flags, F_OLDSTYLE },
876  { "listenaddr", FALSE, PARAM_STRING, &modern_listen, 0 },
877  { "port", FALSE, PARAM_STRING, &modernport, 0 },
878  { "includedir", FALSE, PARAM_STRING, &cfdir, 0 },
879  { "allowlist", FALSE, PARAM_BOOL, &glob_flags, F_LIST },
880  };
881  PARAM* p=gp;
882  int p_size=sizeof(gp)/sizeof(PARAM);
883  GKeyFile *cfile;
884  GError *err = NULL;
885  const char *err_msg=NULL;
886  GQuark errdomain;
887  GArray *retval=NULL;
888  gchar **groups;
889  gboolean bval;
890  gint ival;
891  gint64 i64val;
892  gchar* sval;
893  gchar* startgroup;
894  gint i;
895  gint j;
896 
897  errdomain = g_quark_from_string("parse_cfile");
898  cfile = g_key_file_new();
899  retval = g_array_new(FALSE, TRUE, sizeof(SERVER));
900  if(!g_key_file_load_from_file(cfile, f, G_KEY_FILE_KEEP_COMMENTS |
901  G_KEY_FILE_KEEP_TRANSLATIONS, &err)) {
902  g_set_error(e, errdomain, CFILE_NOTFOUND, "Could not open config file %s.", f);
903  g_key_file_free(cfile);
904  return retval;
905  }
906  startgroup = g_key_file_get_start_group(cfile);
907  if((!startgroup || strcmp(startgroup, "generic")) && have_global) {
908  g_set_error(e, errdomain, CFILE_MISSING_GENERIC, "Config file does not contain the [generic] group!");
909  g_key_file_free(cfile);
910  return NULL;
911  }
912  groups = g_key_file_get_groups(cfile, NULL);
913  for(i=0;groups[i];i++) {
914  memset(&s, '\0', sizeof(SERVER));
915 
916  /* After the [generic] group or when we're parsing an include
917  * directory, start parsing exports */
918  if(i==1 || !have_global) {
919  p=lp;
920  p_size=lp_size;
921  if(!(glob_flags & F_OLDSTYLE)) {
922  lp[1].required = FALSE;
923  }
924  }
925  for(j=0;j<p_size;j++) {
926  assert(p[j].target != NULL);
927  assert(p[j].ptype==PARAM_INT||p[j].ptype==PARAM_STRING||p[j].ptype==PARAM_BOOL||p[j].ptype==PARAM_INT64);
928  switch(p[j].ptype) {
929  case PARAM_INT:
930  ival = g_key_file_get_integer(cfile,
931  groups[i],
932  p[j].paramname,
933  &err);
934  if(!err) {
935  *((gint*)p[j].target) = ival;
936  }
937  break;
938  case PARAM_INT64:
939  i64val = g_key_file_get_int64(cfile,
940  groups[i],
941  p[j].paramname,
942  &err);
943  if(!err) {
944  *((gint64*)p[j].target) = i64val;
945  }
946  break;
947  case PARAM_STRING:
948  sval = g_key_file_get_string(cfile,
949  groups[i],
950  p[j].paramname,
951  &err);
952  if(!err) {
953  *((gchar**)p[j].target) = sval;
954  }
955  break;
956  case PARAM_BOOL:
957  bval = g_key_file_get_boolean(cfile,
958  groups[i],
959  p[j].paramname, &err);
960  if(!err) {
961  if(bval) {
962  *((gint*)p[j].target) |= p[j].flagval;
963  } else {
964  *((gint*)p[j].target) &= ~(p[j].flagval);
965  }
966  }
967  break;
968  }
969  if(err) {
970  if(err->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
971  if(!p[j].required) {
972  /* Ignore not-found error for optional values */
973  g_clear_error(&err);
974  continue;
975  } else {
976  err_msg = MISSING_REQUIRED_ERROR;
977  }
978  } else {
979  err_msg = DEFAULT_ERROR;
980  }
981  g_set_error(e, errdomain, CFILE_VALUE_INVALID, err_msg, p[j].paramname, groups[i], err->message);
982  g_array_free(retval, TRUE);
983  g_error_free(err);
984  g_key_file_free(cfile);
985  return NULL;
986  }
987  }
988  if(virtstyle) {
989  if(!strncmp(virtstyle, "none", 4)) {
991  } else if(!strncmp(virtstyle, "ipliteral", 9)) {
993  } else if(!strncmp(virtstyle, "iphash", 6)) {
995  } else if(!strncmp(virtstyle, "cidrhash", 8)) {
997  if(strlen(virtstyle)<10) {
998  g_set_error(e, errdomain, CFILE_VALUE_INVALID, "Invalid value %s for parameter virtstyle in group %s: missing length", virtstyle, groups[i]);
999  g_array_free(retval, TRUE);
1000  g_key_file_free(cfile);
1001  return NULL;
1002  }
1003  s.cidrlen=strtol(virtstyle+8, NULL, 0);
1004  } else {
1005  g_set_error(e, errdomain, CFILE_VALUE_INVALID, "Invalid value %s for parameter virtstyle in group %s", virtstyle, groups[i]);
1006  g_array_free(retval, TRUE);
1007  g_key_file_free(cfile);
1008  return NULL;
1009  }
1010  } else {
1012  }
1013  if(s.port && !(glob_flags & F_OLDSTYLE)) {
1014  g_warning("A port was specified, but oldstyle exports were not requested. This may not do what you expect.");
1015  g_warning("Please read 'man 5 nbd-server' and search for oldstyle for more info");
1016  }
1017  /* Don't need to free this, it's not our string */
1018  virtstyle=NULL;
1019  /* Don't append values for the [generic] group */
1020  if(i>0 || !have_global) {
1021  s.socket_family = AF_UNSPEC;
1022  s.servename = groups[i];
1023 
1024  append_serve(&s, retval);
1025  }
1026 #ifndef WITH_SDP
1027  if(s.flags & F_SDP) {
1028  g_set_error(e, errdomain, CFILE_VALUE_UNSUPPORTED, "This nbd-server was built without support for SDP, yet group %s uses it", groups[i]);
1029  g_array_free(retval, TRUE);
1030  g_key_file_free(cfile);
1031  return NULL;
1032  }
1033 #endif
1034  }
1035  g_key_file_free(cfile);
1036  if(cfdir) {
1037  GArray* extra = do_cfile_dir(cfdir, e);
1038  if(extra) {
1039  retval = g_array_append_vals(retval, extra->data, extra->len);
1040  i+=extra->len;
1041  g_array_free(extra, TRUE);
1042  } else {
1043  if(*e) {
1044  g_array_free(retval, TRUE);
1045  return NULL;
1046  }
1047  }
1048  }
1049  if(i==1 && have_global) {
1050  g_set_error(e, errdomain, CFILE_NO_EXPORTS, "The config file does not specify any exports");
1051  }
1052  return retval;
1053 }
1054 
1055 /**
1056  * Signal handler for SIGCHLD
1057  * @param s the signal we're handling (must be SIGCHLD, or something
1058  * is severely wrong)
1059  **/
1060 void sigchld_handler(int s) {
1061  int status;
1062  int* i;
1063  pid_t pid;
1064 
1065  while((pid=waitpid(-1, &status, WNOHANG)) > 0) {
1066  if(WIFEXITED(status)) {
1067  msg3(LOG_INFO, "Child exited with %d", WEXITSTATUS(status));
1068  }
1069  i=g_hash_table_lookup(children, &pid);
1070  if(!i) {
1071  msg3(LOG_INFO, "SIGCHLD received for an unknown child with PID %ld", (long)pid);
1072  } else {
1073  DEBUG("Removing %d from the list of children", pid);
1074  g_hash_table_remove(children, &pid);
1075  }
1076  }
1077 }
1078 
1079 /**
1080  * Kill a child. Called from sigterm_handler::g_hash_table_foreach.
1081  *
1082  * @param key the key
1083  * @param value the value corresponding to the above key
1084  * @param user_data a pointer which we always set to 1, so that we know what
1085  * will happen next.
1086  **/
1087 void killchild(gpointer key, gpointer value, gpointer user_data) {
1088  pid_t *pid=value;
1089  int *parent=user_data;
1090 
1091  kill(*pid, SIGTERM);
1092  *parent=1;
1093 }
1094 
1095 /**
1096  * Handle SIGTERM and dispatch it to our children
1097  * @param s the signal we're handling (must be SIGTERM, or something
1098  * is severely wrong).
1099  **/
1100 void sigterm_handler(int s) {
1101  int parent=0;
1102 
1103  g_hash_table_foreach(children, killchild, &parent);
1104 
1105  if(parent) {
1106  unlink(pidfname);
1107  }
1108 
1109  exit(EXIT_SUCCESS);
1110 }
1111 
1112 /**
1113  * Detect the size of a file.
1114  *
1115  * @param fhandle An open filedescriptor
1116  * @return the size of the file, or OFFT_MAX if detection was
1117  * impossible.
1118  **/
1119 off_t size_autodetect(int fhandle) {
1120  off_t es;
1121  u64 bytes __attribute__((unused));
1122  struct stat stat_buf;
1123  int error;
1124 
1125 #ifdef HAVE_SYS_MOUNT_H
1126 #ifdef HAVE_SYS_IOCTL_H
1127 #ifdef BLKGETSIZE64
1128  DEBUG("looking for export size with ioctl BLKGETSIZE64\n");
1129  if (!ioctl(fhandle, BLKGETSIZE64, &bytes) && bytes) {
1130  return (off_t)bytes;
1131  }
1132 #endif /* BLKGETSIZE64 */
1133 #endif /* HAVE_SYS_IOCTL_H */
1134 #endif /* HAVE_SYS_MOUNT_H */
1135 
1136  DEBUG("looking for fhandle size with fstat\n");
1137  stat_buf.st_size = 0;
1138  error = fstat(fhandle, &stat_buf);
1139  if (!error) {
1140  /* always believe stat if a regular file as it might really
1141  * be zero length */
1142  if (S_ISREG(stat_buf.st_mode) || (stat_buf.st_size > 0))
1143  return (off_t)stat_buf.st_size;
1144  } else {
1145  err("fstat failed: %m");
1146  }
1147 
1148  DEBUG("looking for fhandle size with lseek SEEK_END\n");
1149  es = lseek(fhandle, (off_t)0, SEEK_END);
1150  if (es > ((off_t)0)) {
1151  return es;
1152  } else {
1153  DEBUG("lseek failed: %d", errno==EBADF?1:(errno==ESPIPE?2:(errno==EINVAL?3:4)));
1154  }
1155 
1156  err("Could not find size of exported block device: %m");
1157  return OFFT_MAX;
1158 }
1159 
1160 /**
1161  * Get the file handle and offset, given an export offset.
1162  *
1163  * @param export An array of export files
1164  * @param a The offset to get corresponding file/offset for
1165  * @param fhandle [out] File descriptor
1166  * @param foffset [out] Offset into fhandle
1167  * @param maxbytes [out] Tells how many bytes can be read/written
1168  * from fhandle starting at foffset (0 if there is no limit)
1169  * @return 0 on success, -1 on failure
1170  **/
1171 int get_filepos(GArray* export, off_t a, int* fhandle, off_t* foffset, size_t* maxbytes ) {
1172  /* Negative offset not allowed */
1173  if(a < 0)
1174  return -1;
1175 
1176  /* Binary search for last file with starting offset <= a */
1177  FILE_INFO fi;
1178  int start = 0;
1179  int end = export->len - 1;
1180  while( start <= end ) {
1181  int mid = (start + end) / 2;
1182  fi = g_array_index(export, FILE_INFO, mid);
1183  if( fi.startoff < a ) {
1184  start = mid + 1;
1185  } else if( fi.startoff > a ) {
1186  end = mid - 1;
1187  } else {
1188  start = end = mid;
1189  break;
1190  }
1191  }
1192 
1193  /* end should never go negative, since first startoff is 0 and a >= 0 */
1194  assert(end >= 0);
1195 
1196  fi = g_array_index(export, FILE_INFO, end);
1197  *fhandle = fi.fhandle;
1198  *foffset = a - fi.startoff;
1199  *maxbytes = 0;
1200  if( end+1 < export->len ) {
1201  FILE_INFO fi_next = g_array_index(export, FILE_INFO, end+1);
1202  *maxbytes = fi_next.startoff - a;
1203  }
1204 
1205  return 0;
1206 }
1207 
1208 /**
1209  * seek to a position in a file, with error handling.
1210  * @param handle a filedescriptor
1211  * @param a position to seek to
1212  * @todo get rid of this; lastpoint is a global variable right now, but it
1213  * shouldn't be. If we pass it on as a parameter, that makes things a *lot*
1214  * easier.
1215  **/
1216 void myseek(int handle,off_t a) {
1217  if (lseek(handle, a, SEEK_SET) < 0) {
1218  err("Can not seek locally!\n");
1219  }
1220 }
1221 
1222 /**
1223  * Write an amount of bytes at a given offset to the right file. This
1224  * abstracts the write-side of the multiple file option.
1225  *
1226  * @param a The offset where the write should start
1227  * @param buf The buffer to write from
1228  * @param len The length of buf
1229  * @param client The client we're serving for
1230  * @param fua Flag to indicate 'Force Unit Access'
1231  * @return The number of bytes actually written, or -1 in case of an error
1232  **/
1233 ssize_t rawexpwrite(off_t a, char *buf, size_t len, CLIENT *client, int fua) {
1234  int fhandle;
1235  off_t foffset;
1236  size_t maxbytes;
1237  ssize_t retval;
1238 
1239  if(get_filepos(client->export, a, &fhandle, &foffset, &maxbytes))
1240  return -1;
1241  if(maxbytes && len > maxbytes)
1242  len = maxbytes;
1243 
1244  DEBUG("(WRITE to fd %d offset %llu len %u fua %d), ", fhandle, (long long unsigned)foffset, (unsigned int)len, fua);
1245 
1246  myseek(fhandle, foffset);
1247  retval = write(fhandle, buf, len);
1248  if(client->server->flags & F_SYNC) {
1249  fsync(fhandle);
1250  } else if (fua) {
1251 
1252  /* This is where we would do the following
1253  * #ifdef USE_SYNC_FILE_RANGE
1254  * However, we don't, for the reasons set out below
1255  * by Christoph Hellwig <hch@infradead.org>
1256  *
1257  * [BEGINS]
1258  * fdatasync is equivalent to fsync except that it does not flush
1259  * non-essential metadata (basically just timestamps in practice), but it
1260  * does flush metadata requried to find the data again, e.g. allocation
1261  * information and extent maps. sync_file_range does nothing but flush
1262  * out pagecache content - it means you basically won't get your data
1263  * back in case of a crash if you either:
1264  *
1265  * a) have a volatile write cache in your disk (e.g. any normal SATA disk)
1266  * b) are using a sparse file on a filesystem
1267  * c) are using a fallocate-preallocated file on a filesystem
1268  * d) use any file on a COW filesystem like btrfs
1269  *
1270  * e.g. it only does anything useful for you if you do not have a volatile
1271  * write cache, and either use a raw block device node, or just overwrite
1272  * an already fully allocated (and not preallocated) file on a non-COW
1273  * filesystem.
1274  * [ENDS]
1275  *
1276  * What we should do is open a second FD with O_DSYNC set, then write to
1277  * that when appropriate. However, with a Linux client, every REQ_FUA
1278  * immediately follows a REQ_FLUSH, so fdatasync does not cause performance
1279  * problems.
1280  *
1281  */
1282 #if 0
1283  sync_file_range(fhandle, foffset, len,
1284  SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE |
1285  SYNC_FILE_RANGE_WAIT_AFTER);
1286 #else
1287  fdatasync(fhandle);
1288 #endif
1289  }
1290  return retval;
1291 }
1292 
1293 /**
1294  * Call rawexpwrite repeatedly until all data has been written.
1295  *
1296  * @param a The offset where the write should start
1297  * @param buf The buffer to write from
1298  * @param len The length of buf
1299  * @param client The client we're serving for
1300  * @param fua Flag to indicate 'Force Unit Access'
1301  * @return 0 on success, nonzero on failure
1302  **/
1303 int rawexpwrite_fully(off_t a, char *buf, size_t len, CLIENT *client, int fua) {
1304  ssize_t ret=0;
1305 
1306  while(len > 0 && (ret=rawexpwrite(a, buf, len, client, fua)) > 0 ) {
1307  a += ret;
1308  buf += ret;
1309  len -= ret;
1310  }
1311  return (ret < 0 || len != 0);
1312 }
1313 
1314 /**
1315  * Read an amount of bytes at a given offset from the right file. This
1316  * abstracts the read-side of the multiple files option.
1317  *
1318  * @param a The offset where the read should start
1319  * @param buf A buffer to read into
1320  * @param len The size of buf
1321  * @param client The client we're serving for
1322  * @return The number of bytes actually read, or -1 in case of an
1323  * error.
1324  **/
1325 ssize_t rawexpread(off_t a, char *buf, size_t len, CLIENT *client) {
1326  int fhandle;
1327  off_t foffset;
1328  size_t maxbytes;
1329 
1330  if(get_filepos(client->export, a, &fhandle, &foffset, &maxbytes))
1331  return -1;
1332  if(maxbytes && len > maxbytes)
1333  len = maxbytes;
1334 
1335  DEBUG("(READ from fd %d offset %llu len %u), ", fhandle, (long long unsigned int)foffset, (unsigned int)len);
1336 
1337  myseek(fhandle, foffset);
1338  return read(fhandle, buf, len);
1339 }
1340 
1341 /**
1342  * Call rawexpread repeatedly until all data has been read.
1343  * @return 0 on success, nonzero on failure
1344  **/
1345 int rawexpread_fully(off_t a, char *buf, size_t len, CLIENT *client) {
1346  ssize_t ret=0;
1347 
1348  while(len > 0 && (ret=rawexpread(a, buf, len, client)) > 0 ) {
1349  a += ret;
1350  buf += ret;
1351  len -= ret;
1352  }
1353  return (ret < 0 || len != 0);
1354 }
1355 
1356 /**
1357  * Read an amount of bytes at a given offset from the right file. This
1358  * abstracts the read-side of the copyonwrite stuff, and calls
1359  * rawexpread() with the right parameters to do the actual work.
1360  * @param a The offset where the read should start
1361  * @param buf A buffer to read into
1362  * @param len The size of buf
1363  * @param client The client we're going to read for
1364  * @return 0 on success, nonzero on failure
1365  **/
1366 int expread(off_t a, char *buf, size_t len, CLIENT *client) {
1367  off_t rdlen, offset;
1368  off_t mapcnt, mapl, maph, pagestart;
1369 
1370  if (!(client->server->flags & F_COPYONWRITE))
1371  return(rawexpread_fully(a, buf, len, client));
1372  DEBUG("Asked to read %u bytes at %llu.\n", (unsigned int)len, (unsigned long long)a);
1373 
1374  mapl=a/DIFFPAGESIZE; maph=(a+len-1)/DIFFPAGESIZE;
1375 
1376  for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
1377  pagestart=mapcnt*DIFFPAGESIZE;
1378  offset=a-pagestart;
1379  rdlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
1380  len : (size_t)DIFFPAGESIZE-offset;
1381  if (client->difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
1382  DEBUG("Page %llu is at %lu\n", (unsigned long long)mapcnt,
1383  (unsigned long)(client->difmap[mapcnt]));
1384  myseek(client->difffile, client->difmap[mapcnt]*DIFFPAGESIZE+offset);
1385  if (read(client->difffile, buf, rdlen) != rdlen) return -1;
1386  } else { /* the block is not there */
1387  DEBUG("Page %llu is not here, we read the original one\n",
1388  (unsigned long long)mapcnt);
1389  if(rawexpread_fully(a, buf, rdlen, client)) return -1;
1390  }
1391  len-=rdlen; a+=rdlen; buf+=rdlen;
1392  }
1393  return 0;
1394 }
1395 
1396 /**
1397  * Write an amount of bytes at a given offset to the right file. This
1398  * abstracts the write-side of the copyonwrite option, and calls
1399  * rawexpwrite() with the right parameters to do the actual work.
1400  *
1401  * @param a The offset where the write should start
1402  * @param buf The buffer to write from
1403  * @param len The length of buf
1404  * @param client The client we're going to write for.
1405  * @param fua Flag to indicate 'Force Unit Access'
1406  * @return 0 on success, nonzero on failure
1407  **/
1408 int expwrite(off_t a, char *buf, size_t len, CLIENT *client, int fua) {
1409  char pagebuf[DIFFPAGESIZE];
1410  off_t mapcnt,mapl,maph;
1411  off_t wrlen,rdlen;
1412  off_t pagestart;
1413  off_t offset;
1414 
1415  if (!(client->server->flags & F_COPYONWRITE))
1416  return(rawexpwrite_fully(a, buf, len, client, fua));
1417  DEBUG("Asked to write %u bytes at %llu.\n", (unsigned int)len, (unsigned long long)a);
1418 
1419  mapl=a/DIFFPAGESIZE ; maph=(a+len-1)/DIFFPAGESIZE ;
1420 
1421  for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
1422  pagestart=mapcnt*DIFFPAGESIZE ;
1423  offset=a-pagestart ;
1424  wrlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
1425  len : (size_t)DIFFPAGESIZE-offset;
1426 
1427  if (client->difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
1428  DEBUG("Page %llu is at %lu\n", (unsigned long long)mapcnt,
1429  (unsigned long)(client->difmap[mapcnt])) ;
1430  myseek(client->difffile,
1431  client->difmap[mapcnt]*DIFFPAGESIZE+offset);
1432  if (write(client->difffile, buf, wrlen) != wrlen) return -1 ;
1433  } else { /* the block is not there */
1434  myseek(client->difffile,client->difffilelen*DIFFPAGESIZE) ;
1435  client->difmap[mapcnt]=(client->server->flags&F_SPARSE)?mapcnt:client->difffilelen++;
1436  DEBUG("Page %llu is not here, we put it at %lu\n",
1437  (unsigned long long)mapcnt,
1438  (unsigned long)(client->difmap[mapcnt]));
1439  rdlen=DIFFPAGESIZE ;
1440  if (rawexpread_fully(pagestart, pagebuf, rdlen, client))
1441  return -1;
1442  memcpy(pagebuf+offset,buf,wrlen) ;
1443  if (write(client->difffile, pagebuf, DIFFPAGESIZE) !=
1444  DIFFPAGESIZE)
1445  return -1;
1446  }
1447  len-=wrlen ; a+=wrlen ; buf+=wrlen ;
1448  }
1449  if (client->server->flags & F_SYNC) {
1450  fsync(client->difffile);
1451  } else if (fua) {
1452  /* open question: would it be cheaper to do multiple sync_file_ranges?
1453  as we iterate through the above?
1454  */
1455  fdatasync(client->difffile);
1456  }
1457  return 0;
1458 }
1459 
1460 /**
1461  * Flush data to a client
1462  *
1463  * @param client The client we're going to write for.
1464  * @return 0 on success, nonzero on failure
1465  **/
1466 int expflush(CLIENT *client) {
1467  gint i;
1468 
1469  if (client->server->flags & F_COPYONWRITE) {
1470  return fsync(client->difffile);
1471  }
1472 
1473  for (i = 0; i < client->export->len; i++) {
1474  FILE_INFO fi = g_array_index(client->export, FILE_INFO, i);
1475  if (fsync(fi.fhandle) < 0)
1476  return -1;
1477  }
1478 
1479  return 0;
1480 }
1481 
1482 /*
1483  * If the current system supports it, call fallocate() on the backend
1484  * file to resparsify stuff that isn't needed anymore (see NBD_CMD_TRIM)
1485  */
1486 int exptrim(struct nbd_request* req, CLIENT* client) {
1487 #if HAVE_FALLOC_PH
1488  FILE_INFO prev = g_array_index(client->export, FILE_INFO, 0);
1489  FILE_INFO cur = prev;
1490  int i = 1;
1491  /* We're running on a system that supports the
1492  * FALLOC_FL_PUNCH_HOLE option to re-sparsify a file */
1493  do {
1494  if(i<client->export->len) {
1495  cur = g_array_index(client->export, FILE_INFO, i);
1496  }
1497  if(prev.startoff < req->from) {
1498  off_t curoff = req->from - prev.startoff;
1499  off_t curlen = cur.startoff - prev.startoff - curoff;
1500  fallocate(prev.fhandle, FALLOC_FL_PUNCH_HOLE, curoff, curlen);
1501  }
1502  prev = cur;
1503  } while(i < client->export->len && cur.startoff < (req->from + req->len));
1504  DEBUG("Performed TRIM request from %llu to %llu", (unsigned long long) req->from, (unsigned long long) req->len);
1505 #else
1506  DEBUG("Ignoring TRIM request (not supported on current platform");
1507 #endif
1508  return 0;
1509 }
1510 
1511 static void send_reply(uint32_t opt, int net, uint32_t reply_type, size_t datasize, void* data) {
1512  uint64_t magic = htonll(0x3e889045565a9LL);
1513  reply_type = htonl(reply_type);
1514  uint32_t datsize = htonl(datasize);
1515  struct iovec v_data[] = {
1516  { &magic, sizeof(magic) },
1517  { &opt, sizeof(opt) },
1518  { &reply_type, sizeof(reply_type) },
1519  { &datsize, sizeof(datsize) },
1520  { data, datasize },
1521  };
1522  writev(net, v_data, 5);
1523 }
1524 
1525 static CLIENT* handle_export_name(uint32_t opt, int net, GArray* servers, uint32_t cflags) {
1526  uint32_t namelen;
1527  char* name;
1528  int i;
1529 
1530  if (read(net, &namelen, sizeof(namelen)) < 0)
1531  err("Negotiation failed/7: %m");
1532  namelen = ntohl(namelen);
1533  name = malloc(namelen+1);
1534  name[namelen]=0;
1535  if (read(net, name, namelen) < 0)
1536  err("Negotiation failed/8: %m");
1537  for(i=0; i<servers->len; i++) {
1538  SERVER* serve = &(g_array_index(servers, SERVER, i));
1539  if(!strcmp(serve->servename, name)) {
1540  CLIENT* client = g_new0(CLIENT, 1);
1541  client->server = serve;
1542  client->exportsize = OFFT_MAX;
1543  client->net = net;
1544  client->modern = TRUE;
1545  client->transactionlogfd = -1;
1546  client->clientfeats = cflags;
1547  free(name);
1548  return client;
1549  }
1550  }
1551  free(name);
1552  return NULL;
1553 }
1554 
1555 static void handle_list(uint32_t opt, int net, GArray* servers, uint32_t cflags) {
1556  uint32_t len;
1557  int i;
1558  char buf[1024];
1559  char *ptr = buf + sizeof(len);
1560 
1561  if (read(net, &len, sizeof(len)) < 0)
1562  err("Negotiation failed/8: %m");
1563  len = ntohl(len);
1564  if(len) {
1565  send_reply(opt, net, NBD_REP_ERR_INVALID, 0, NULL);
1566  }
1567  if(!(glob_flags & F_LIST)) {
1568  send_reply(opt, net, NBD_REP_ERR_POLICY, 0, NULL);
1569  err_nonfatal("Client tried disallowed list option");
1570  return;
1571  }
1572  for(i=0; i<servers->len; i++) {
1573  SERVER* serve = &(g_array_index(servers, SERVER, i));
1574  len = htonl(strlen(serve->servename));
1575  memcpy(buf, &len, sizeof(len));
1576  strcpy(ptr, serve->servename);
1577  send_reply(opt, net, NBD_REP_SERVER, strlen(serve->servename)+sizeof(len), buf);
1578  }
1579  send_reply(opt, net, NBD_REP_ACK, 0, NULL);
1580 }
1581 
1582 /**
1583  * Do the initial negotiation.
1584  *
1585  * @param client The client we're negotiating with.
1586  **/
1587 CLIENT* negotiate(int net, CLIENT *client, GArray* servers, int phase) {
1588  char zeros[128];
1589  uint64_t size_host;
1590  uint32_t flags = NBD_FLAG_HAS_FLAGS;
1591  uint16_t smallflags = 0;
1592  uint64_t magic;
1593 
1594  memset(zeros, '\0', sizeof(zeros));
1595  assert(((phase & NEG_INIT) && (phase & NEG_MODERN)) || client);
1596  if(phase & NEG_MODERN) {
1597  smallflags |= NBD_FLAG_FIXED_NEWSTYLE;
1598  }
1599  if(phase & NEG_INIT) {
1600  /* common */
1601  if (write(net, INIT_PASSWD, 8) < 0) {
1602  err_nonfatal("Negotiation failed/1: %m");
1603  if(client)
1604  exit(EXIT_FAILURE);
1605  }
1606  if(phase & NEG_MODERN) {
1607  /* modern */
1608  magic = htonll(opts_magic);
1609  } else {
1610  /* oldstyle */
1611  magic = htonll(cliserv_magic);
1612  }
1613  if (write(net, &magic, sizeof(magic)) < 0) {
1614  err_nonfatal("Negotiation failed/2: %m");
1615  if(phase & NEG_OLD)
1616  exit(EXIT_FAILURE);
1617  }
1618  }
1619  if ((phase & NEG_MODERN) && (phase & NEG_INIT)) {
1620  /* modern */
1621  uint32_t cflags;
1622  uint32_t opt;
1623 
1624  if(!servers)
1625  err("programmer error");
1626  smallflags = htons(smallflags);
1627  if (write(net, &smallflags, sizeof(uint16_t)) < 0)
1628  err_nonfatal("Negotiation failed/3: %m");
1629  if (read(net, &cflags, sizeof(cflags)) < 0)
1630  err_nonfatal("Negotiation failed/4: %m");
1631  cflags = htonl(cflags);
1632  do {
1633  if (read(net, &magic, sizeof(magic)) < 0)
1634  err_nonfatal("Negotiation failed/5: %m");
1635  magic = ntohll(magic);
1636  if(magic != opts_magic) {
1637  close(net);
1638  return NULL;
1639  }
1640  if (read(net, &opt, sizeof(opt)) < 0)
1641  err_nonfatal("Negotiation failed/6: %m");
1642  opt = ntohl(opt);
1643  switch(opt) {
1644  case NBD_OPT_EXPORT_NAME:
1645  // NBD_OPT_EXPORT_NAME must be the last
1646  // selected option, so return from here
1647  // if that is chosen.
1648  return handle_export_name(opt, net, servers, cflags);
1649  break;
1650  case NBD_OPT_LIST:
1651  handle_list(opt, net, servers, cflags);
1652  break;
1653  case NBD_OPT_ABORT:
1654  // handled below
1655  break;
1656  default:
1657  send_reply(opt, net, NBD_REP_ERR_UNSUP, 0, NULL);
1658  break;
1659  }
1660  } while((opt != NBD_OPT_EXPORT_NAME) && (opt != NBD_OPT_ABORT));
1661  if(opt == NBD_OPT_ABORT) {
1662  close(net);
1663  return NULL;
1664  }
1665  }
1666  /* common */
1667  size_host = htonll((u64)(client->exportsize));
1668  if (write(net, &size_host, 8) < 0)
1669  err("Negotiation failed/9: %m");
1670  if (client->server->flags & F_READONLY)
1671  flags |= NBD_FLAG_READ_ONLY;
1672  if (client->server->flags & F_FLUSH)
1673  flags |= NBD_FLAG_SEND_FLUSH;
1674  if (client->server->flags & F_FUA)
1675  flags |= NBD_FLAG_SEND_FUA;
1676  if (client->server->flags & F_ROTATIONAL)
1677  flags |= NBD_FLAG_ROTATIONAL;
1678  if (client->server->flags & F_TRIM)
1679  flags |= NBD_FLAG_SEND_TRIM;
1680  if (phase & NEG_OLD) {
1681  /* oldstyle */
1682  flags = htonl(flags);
1683  if (write(client->net, &flags, 4) < 0)
1684  err("Negotiation failed/10: %m");
1685  } else {
1686  /* modern */
1687  smallflags = (uint16_t)(flags & ~((uint16_t)0));
1688  smallflags = htons(smallflags);
1689  if (write(client->net, &smallflags, sizeof(smallflags)) < 0) {
1690  err("Negotiation failed/11: %m");
1691  }
1692  }
1693  /* common */
1694  if (write(client->net, zeros, 124) < 0)
1695  err("Negotiation failed/12: %m");
1696  return NULL;
1697 }
1698 
1699 /** sending macro. */
1700 #define SEND(net,reply) { writeit( net, &reply, sizeof( reply )); \
1701  if (client->transactionlogfd != -1) \
1702  writeit(client->transactionlogfd, &reply, sizeof(reply)); }
1703 /** error macro. */
1704 #define ERROR(client,reply,errcode) { reply.error = htonl(errcode); SEND(client->net,reply); reply.error = 0; }
1705 /**
1706  * Serve a file to a single client.
1707  *
1708  * @todo This beast needs to be split up in many tiny little manageable
1709  * pieces. Preferably with a chainsaw.
1710  *
1711  * @param client The client we're going to serve to.
1712  * @return when the client disconnects
1713  **/
1714 int mainloop(CLIENT *client) {
1715  struct nbd_request request;
1716  struct nbd_reply reply;
1717  gboolean go_on=TRUE;
1718 #ifdef DODBG
1719  int i = 0;
1720 #endif
1721  negotiate(client->net, client, NULL, client->modern ? NEG_MODERN : (NEG_OLD | NEG_INIT));
1722  DEBUG("Entering request loop!\n");
1723  reply.magic = htonl(NBD_REPLY_MAGIC);
1724  reply.error = 0;
1725  while (go_on) {
1726  char buf[BUFSIZE];
1727  char* p;
1728  size_t len;
1729  size_t currlen;
1730  size_t writelen;
1731  uint16_t command;
1732 #ifdef DODBG
1733  i++;
1734  printf("%d: ", i);
1735 #endif
1736  readit(client->net, &request, sizeof(request));
1737  if (client->transactionlogfd != -1)
1738  writeit(client->transactionlogfd, &request, sizeof(request));
1739 
1740  request.from = ntohll(request.from);
1741  request.type = ntohl(request.type);
1742  command = request.type & NBD_CMD_MASK_COMMAND;
1743  len = ntohl(request.len);
1744 
1745  DEBUG("%s from %llu (%llu) len %d, ", getcommandname(command),
1746  (unsigned long long)request.from,
1747  (unsigned long long)request.from / 512, (unsigned int)len);
1748 
1749  if (request.magic != htonl(NBD_REQUEST_MAGIC))
1750  err("Not enough magic.");
1751 
1752  memcpy(reply.handle, request.handle, sizeof(reply.handle));
1753 
1754  if ((command==NBD_CMD_WRITE) || (command==NBD_CMD_READ)) {
1755  if ((request.from + len) > (OFFT_MAX)) {
1756  DEBUG("[Number too large!]");
1757  ERROR(client, reply, EINVAL);
1758  continue;
1759  }
1760 
1761  if (((ssize_t)((off_t)request.from + len) > client->exportsize)) {
1762  DEBUG("[RANGE!]");
1763  ERROR(client, reply, EINVAL);
1764  continue;
1765  }
1766 
1767  currlen = len;
1768  if (currlen > BUFSIZE - sizeof(struct nbd_reply)) {
1769  currlen = BUFSIZE - sizeof(struct nbd_reply);
1770  if(!logged_oversized) {
1771  msg2(LOG_DEBUG, "oversized request (this is not a problem)");
1772  logged_oversized = true;
1773  }
1774  }
1775  }
1776 
1777  switch (command) {
1778 
1779  case NBD_CMD_DISC:
1780  msg2(LOG_INFO, "Disconnect request received.");
1781  if (client->server->flags & F_COPYONWRITE) {
1782  if (client->difmap) g_free(client->difmap) ;
1783  close(client->difffile);
1784  unlink(client->difffilename);
1785  free(client->difffilename);
1786  }
1787  go_on=FALSE;
1788  continue;
1789 
1790  case NBD_CMD_WRITE:
1791  DEBUG("wr: net->buf, ");
1792  while(len > 0) {
1793  readit(client->net, buf, currlen);
1794  DEBUG("buf->exp, ");
1795  if ((client->server->flags & F_READONLY) ||
1796  (client->server->flags & F_AUTOREADONLY)) {
1797  DEBUG("[WRITE to READONLY!]");
1798  ERROR(client, reply, EPERM);
1799  consume(client->net, buf, len-currlen, BUFSIZE);
1800  continue;
1801  }
1802  if (expwrite(request.from, buf, currlen, client,
1803  request.type & NBD_CMD_FLAG_FUA)) {
1804  DEBUG("Write failed: %m" );
1805  ERROR(client, reply, errno);
1806  consume(client->net, buf, len-currlen, BUFSIZE);
1807  continue;
1808  }
1809  len -= currlen;
1810  request.from += currlen;
1811  currlen = (len < BUFSIZE) ? len : BUFSIZE;
1812  }
1813  SEND(client->net, reply);
1814  DEBUG("OK!\n");
1815  continue;
1816 
1817  case NBD_CMD_FLUSH:
1818  DEBUG("fl: ");
1819  if (expflush(client)) {
1820  DEBUG("Flush failed: %m");
1821  ERROR(client, reply, errno);
1822  continue;
1823  }
1824  SEND(client->net, reply);
1825  DEBUG("OK!\n");
1826  continue;
1827 
1828  case NBD_CMD_READ:
1829  DEBUG("exp->buf, ");
1830  memcpy(buf, &reply, sizeof(struct nbd_reply));
1831  if (client->transactionlogfd != -1)
1832  writeit(client->transactionlogfd, &reply, sizeof(reply));
1833  p = buf + sizeof(struct nbd_reply);
1834  writelen = currlen + sizeof(struct nbd_reply);
1835  while(len > 0) {
1836  if (expread(request.from, p, currlen, client)) {
1837  DEBUG("Read failed: %m");
1838  ERROR(client, reply, errno);
1839  continue;
1840  }
1841 
1842  DEBUG("buf->net, ");
1843  writeit(client->net, buf, writelen);
1844  len -= currlen;
1845  request.from += currlen;
1846  currlen = (len < BUFSIZE) ? len : BUFSIZE;
1847  p = buf;
1848  writelen = currlen;
1849  }
1850  DEBUG("OK!\n");
1851  continue;
1852 
1853  case NBD_CMD_TRIM:
1854  /* The kernel module sets discard_zeroes_data == 0,
1855  * so it is okay to do nothing. */
1856  if (exptrim(&request, client)) {
1857  DEBUG("Trim failed: %m");
1858  ERROR(client, reply, errno);
1859  continue;
1860  }
1861  SEND(client->net, reply);
1862  continue;
1863 
1864  default:
1865  DEBUG ("Ignoring unknown command\n");
1866  continue;
1867  }
1868  }
1869  return 0;
1870 }
1871 
1872 /**
1873  * Set up client export array, which is an array of FILE_INFO.
1874  * Also, split a single exportfile into multiple ones, if that was asked.
1875  * @param client information on the client which we want to setup export for
1876  **/
1877 void setupexport(CLIENT* client) {
1878  int i;
1879  off_t laststartoff = 0, lastsize = 0;
1880  int multifile = (client->server->flags & F_MULTIFILE);
1881  int temporary = (client->server->flags & F_TEMPORARY) && !multifile;
1882  int cancreate = (client->server->expected_size) && !multifile;
1883 
1884  client->export = g_array_new(TRUE, TRUE, sizeof(FILE_INFO));
1885 
1886  /* If multi-file, open as many files as we can.
1887  * If not, open exactly one file.
1888  * Calculate file sizes as we go to get total size. */
1889  for(i=0; ; i++) {
1890  FILE_INFO fi;
1891  gchar *tmpname;
1892  gchar* error_string;
1893 
1894  if (i)
1895  cancreate = 0;
1896  /* if expected_size is specified, and this is the first file, we can create the file */
1897  mode_t mode = (client->server->flags & F_READONLY) ?
1898  O_RDONLY : (O_RDWR | (cancreate?O_CREAT:0));
1899 
1900  if (temporary) {
1901  tmpname=g_strdup_printf("%s.%d-XXXXXX", client->exportname, i);
1902  DEBUG( "Opening %s\n", tmpname );
1903  fi.fhandle = mkstemp(tmpname);
1904  } else {
1905  if(multifile) {
1906  tmpname=g_strdup_printf("%s.%d", client->exportname, i);
1907  } else {
1908  tmpname=g_strdup(client->exportname);
1909  }
1910  DEBUG( "Opening %s\n", tmpname );
1911  fi.fhandle = open(tmpname, mode, 0x600);
1912  if(fi.fhandle == -1 && mode == O_RDWR) {
1913  /* Try again because maybe media was read-only */
1914  fi.fhandle = open(tmpname, O_RDONLY);
1915  if(fi.fhandle != -1) {
1916  /* Opening the base file in copyonwrite mode is
1917  * okay */
1918  if(!(client->server->flags & F_COPYONWRITE)) {
1919  client->server->flags |= F_AUTOREADONLY;
1920  client->server->flags |= F_READONLY;
1921  }
1922  }
1923  }
1924  }
1925  if(fi.fhandle == -1) {
1926  if(multifile && i>0)
1927  break;
1928  error_string=g_strdup_printf(
1929  "Could not open exported file %s: %%m",
1930  tmpname);
1931  err(error_string);
1932  }
1933 
1934  if (temporary)
1935  unlink(tmpname); /* File will stick around whilst FD open */
1936 
1937  fi.startoff = laststartoff + lastsize;
1938  g_array_append_val(client->export, fi);
1939  g_free(tmpname);
1940 
1941  /* Starting offset and size of this file will be used to
1942  * calculate starting offset of next file */
1943  laststartoff = fi.startoff;
1944  lastsize = size_autodetect(fi.fhandle);
1945 
1946  /* If we created the file, it will be length zero */
1947  if (!lastsize && cancreate) {
1948  assert(!multifile);
1949  if(ftruncate (fi.fhandle, client->server->expected_size)<0) {
1950  err("Could not expand file: %m");
1951  }
1952  lastsize = client->server->expected_size;
1953  break; /* don't look for any more files */
1954  }
1955 
1956  if(!multifile || temporary)
1957  break;
1958  }
1959 
1960  /* Set export size to total calculated size */
1961  client->exportsize = laststartoff + lastsize;
1962 
1963  /* Export size may be overridden */
1964  if(client->server->expected_size) {
1965  /* desired size must be <= total calculated size */
1966  if(client->server->expected_size > client->exportsize) {
1967  err("Size of exported file is too big\n");
1968  }
1969 
1970  client->exportsize = client->server->expected_size;
1971  }
1972 
1973  msg3(LOG_INFO, "Size of exported file/device is %llu", (unsigned long long)client->exportsize);
1974  if(multifile) {
1975  msg3(LOG_INFO, "Total number of files: %d", i);
1976  }
1977 }
1978 
1980  off_t i;
1981  if ((client->difffilename = malloc(1024))==NULL)
1982  err("Failed to allocate string for diff file name");
1983  snprintf(client->difffilename, 1024, "%s-%s-%d.diff",client->exportname,client->clientname,
1984  (int)getpid()) ;
1985  client->difffilename[1023]='\0';
1986  msg3(LOG_INFO,"About to create map and diff file %s",client->difffilename) ;
1987  client->difffile=open(client->difffilename,O_RDWR | O_CREAT | O_TRUNC,0600) ;
1988  if (client->difffile<0) err("Could not create diff file (%m)") ;
1989  if ((client->difmap=calloc(client->exportsize/DIFFPAGESIZE,sizeof(u32)))==NULL)
1990  err("Could not allocate memory") ;
1991  for (i=0;i<client->exportsize/DIFFPAGESIZE;i++) client->difmap[i]=(u32)-1 ;
1992 
1993  return 0;
1994 }
1995 
1996 /**
1997  * Run a command. This is used for the ``prerun'' and ``postrun'' config file
1998  * options
1999  *
2000  * @param command the command to be ran. Read from the config file
2001  * @param file the file name we're about to export
2002  **/
2003 int do_run(gchar* command, gchar* file) {
2004  gchar* cmd;
2005  int retval=0;
2006 
2007  if(command && *command) {
2008  cmd = g_strdup_printf(command, file);
2009  retval=system(cmd);
2010  g_free(cmd);
2011  }
2012  return retval;
2013 }
2014 
2015 /**
2016  * Serve a connection.
2017  *
2018  * @todo allow for multithreading, perhaps use libevent. Not just yet, though;
2019  * follow the road map.
2020  *
2021  * @param client a connected client
2022  **/
2023 void serveconnection(CLIENT *client) {
2024  if (client->server->transactionlog && (client->transactionlogfd == -1))
2025  {
2026  if (-1 == (client->transactionlogfd = open(client->server->transactionlog,
2027  O_WRONLY | O_CREAT,
2028  S_IRUSR | S_IWUSR)))
2029  g_warning("Could not open transaction log %s",
2030  client->server->transactionlog);
2031  }
2032 
2033  if(do_run(client->server->prerun, client->exportname)) {
2034  exit(EXIT_FAILURE);
2035  }
2036  setupexport(client);
2037 
2038  if (client->server->flags & F_COPYONWRITE) {
2039  copyonwrite_prepare(client);
2040  }
2041 
2042  setmysockopt(client->net);
2043 
2044  mainloop(client);
2045  do_run(client->server->postrun, client->exportname);
2046 
2047  if (-1 != client->transactionlogfd)
2048  {
2049  close(client->transactionlogfd);
2050  client->transactionlogfd = -1;
2051  }
2052 }
2053 
2054 /**
2055  * Find the name of the file we have to serve. This will use g_strdup_printf
2056  * to put the IP address of the client inside a filename containing
2057  * "%s" (in the form as specified by the "virtstyle" option). That name
2058  * is then written to client->exportname.
2059  *
2060  * @param net A socket connected to an nbd client
2061  * @param client information about the client. The IP address in human-readable
2062  * format will be written to a new char* buffer, the address of which will be
2063  * stored in client->clientname.
2064  **/
2065 void set_peername(int net, CLIENT *client) {
2066  struct sockaddr_storage addrin;
2067  struct sockaddr_storage netaddr;
2068  struct sockaddr_in *netaddr4 = NULL;
2069  struct sockaddr_in6 *netaddr6 = NULL;
2070  socklen_t addrinlen = sizeof( addrin );
2071  struct addrinfo hints;
2072  struct addrinfo *ai = NULL;
2073  char peername[NI_MAXHOST];
2074  char netname[NI_MAXHOST];
2075  char *tmp = NULL;
2076  int i;
2077  int e;
2078  int shift;
2079 
2080  if (getpeername(net, (struct sockaddr *) &addrin, &addrinlen) < 0)
2081  err("getpeername failed: %m");
2082 
2083  if((e = getnameinfo((struct sockaddr *)&addrin, addrinlen,
2084  peername, sizeof (peername), NULL, 0, NI_NUMERICHOST))) {
2085  msg3(LOG_INFO, "getnameinfo failed: %s", gai_strerror(e));
2086  freeaddrinfo(ai);
2087  }
2088 
2089  memset(&hints, '\0', sizeof (hints));
2090  hints.ai_flags = AI_ADDRCONFIG;
2091  e = getaddrinfo(peername, NULL, &hints, &ai);
2092 
2093  if(e != 0) {
2094  msg3(LOG_INFO, "getaddrinfo failed: %s", gai_strerror(e));
2095  freeaddrinfo(ai);
2096  return;
2097  }
2098 
2099  switch(client->server->virtstyle) {
2100  case VIRT_NONE:
2101  client->exportname=g_strdup(client->server->exportname);
2102  break;
2103  case VIRT_IPHASH:
2104  for(i=0;i<strlen(peername);i++) {
2105  if(peername[i]=='.') {
2106  peername[i]='/';
2107  }
2108  }
2109  case VIRT_IPLIT:
2110  client->exportname=g_strdup_printf(client->server->exportname, peername);
2111  break;
2112  case VIRT_CIDR:
2113  memcpy(&netaddr, &addrin, addrinlen);
2114  if(ai->ai_family == AF_INET) {
2115  netaddr4 = (struct sockaddr_in *)&netaddr;
2116  (netaddr4->sin_addr).s_addr>>=32-(client->server->cidrlen);
2117  (netaddr4->sin_addr).s_addr<<=32-(client->server->cidrlen);
2118 
2119  getnameinfo((struct sockaddr *) netaddr4, addrinlen,
2120  netname, sizeof (netname), NULL, 0, NI_NUMERICHOST);
2121  tmp=g_strdup_printf("%s/%s", netname, peername);
2122  }else if(ai->ai_family == AF_INET6) {
2123  netaddr6 = (struct sockaddr_in6 *)&netaddr;
2124 
2125  shift = 128-(client->server->cidrlen);
2126  i = 3;
2127  while(shift >= 8) {
2128  ((netaddr6->sin6_addr).s6_addr[i])=0;
2129  shift-=8;
2130  i--;
2131  }
2132  (netaddr6->sin6_addr).s6_addr[i]>>=shift;
2133  (netaddr6->sin6_addr).s6_addr[i]<<=shift;
2134 
2135  getnameinfo((struct sockaddr *)netaddr6, addrinlen,
2136  netname, sizeof(netname), NULL, 0, NI_NUMERICHOST);
2137  tmp=g_strdup_printf("%s/%s", netname, peername);
2138  }
2139 
2140  if(tmp != NULL)
2141  client->exportname=g_strdup_printf(client->server->exportname, tmp);
2142 
2143  break;
2144  }
2145 
2146  freeaddrinfo(ai);
2147  msg4(LOG_INFO, "connect from %s, assigned file is %s",
2148  peername, client->exportname);
2149  client->clientname=g_strdup(peername);
2150 }
2151 
2152 /**
2153  * Destroy a pid_t*
2154  * @param data a pointer to pid_t which should be freed
2155  **/
2156 void destroy_pid_t(gpointer data) {
2157  g_free(data);
2158 }
2159 
2160 /**
2161  * Loop through the available servers, and serve them. Never returns.
2162  **/
2163 int serveloop(GArray* servers) {
2164  struct sockaddr_storage addrin;
2165  socklen_t addrinlen=sizeof(addrin);
2166  int i;
2167  int max;
2168  int sock;
2169  fd_set mset;
2170  fd_set rset;
2171 
2172  /*
2173  * Set up the master fd_set. The set of descriptors we need
2174  * to select() for never changes anyway and it buys us a *lot*
2175  * of time to only build this once. However, if we ever choose
2176  * to not fork() for clients anymore, we may have to revisit
2177  * this.
2178  */
2179  max=0;
2180  FD_ZERO(&mset);
2181  for(i=0;i<servers->len;i++) {
2182  if((sock=(g_array_index(servers, SERVER, i)).socket)) {
2183  FD_SET(sock, &mset);
2184  max=sock>max?sock:max;
2185  }
2186  }
2187  if(modernsock) {
2188  FD_SET(modernsock, &mset);
2189  max=modernsock>max?modernsock:max;
2190  }
2191  for(;;) {
2192  CLIENT *client = NULL;
2193  pid_t *pid;
2194 
2195  memcpy(&rset, &mset, sizeof(fd_set));
2196  if(select(max+1, &rset, NULL, NULL, NULL)>0) {
2197  int net = 0;
2198  SERVER* serve=NULL;
2199 
2200  DEBUG("accept, ");
2201  if(FD_ISSET(modernsock, &rset)) {
2202  if((net=accept(modernsock, (struct sockaddr *) &addrin, &addrinlen)) < 0)
2203  err("accept: %m");
2204  client = negotiate(net, NULL, servers, NEG_INIT | NEG_MODERN);
2205  if(!client) {
2206  err_nonfatal("negotiation failed");
2207  close(net);
2208  net=0;
2209  continue;
2210  }
2211  serve = client->server;
2212  }
2213  for(i=0;i<servers->len && !net;i++) {
2214  serve=&(g_array_index(servers, SERVER, i));
2215  if(FD_ISSET(serve->socket, &rset)) {
2216  if ((net=accept(serve->socket, (struct sockaddr *) &addrin, &addrinlen)) < 0)
2217  err("accept: %m");
2218  }
2219  }
2220  if(net) {
2221  int sock_flags;
2222 
2223  if(serve->max_connections > 0 &&
2224  g_hash_table_size(children) >= serve->max_connections) {
2225  msg2(LOG_INFO, "Max connections reached");
2226  close(net);
2227  continue;
2228  }
2229  if((sock_flags = fcntl(net, F_GETFL, 0))==-1) {
2230  err("fcntl F_GETFL");
2231  }
2232  if(fcntl(net, F_SETFL, sock_flags &~O_NONBLOCK)==-1) {
2233  err("fcntl F_SETFL ~O_NONBLOCK");
2234  }
2235  if(!client) {
2236  client = g_new0(CLIENT, 1);
2237  client->server=serve;
2238  client->exportsize=OFFT_MAX;
2239  client->net=net;
2240  client->transactionlogfd = -1;
2241  }
2242  set_peername(net, client);
2243  if (!authorized_client(client)) {
2244  msg2(LOG_INFO,"Unauthorized client") ;
2245  close(net);
2246  continue;
2247  }
2248  msg2(LOG_INFO,"Authorized client") ;
2249  pid=g_malloc(sizeof(pid_t));
2250 
2251  if (!dontfork) {
2252  if ((*pid=fork())<0) {
2253  msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ;
2254  close(net);
2255  continue;
2256  }
2257  if (*pid>0) { /* parent */
2258  close(net);
2259  g_hash_table_insert(children, pid, pid);
2260  continue;
2261  }
2262  /* child */
2263  g_hash_table_destroy(children);
2264  for(i=0;i<servers->len;i++) {
2265  serve=&g_array_index(servers, SERVER, i);
2266  close(serve->socket);
2267  }
2268  /* FALSE does not free the
2269  actual data. This is required,
2270  because the client has a
2271  direct reference into that
2272  data, and otherwise we get a
2273  segfault... */
2274  g_array_free(servers, FALSE);
2275  }
2276 
2277  msg2(LOG_INFO,"Starting to serve");
2278  serveconnection(client);
2279  exit(EXIT_SUCCESS);
2280  }
2281  }
2282  }
2283 }
2284 
2285 void dosockopts(int socket) {
2286 #ifndef sun
2287  int yes=1;
2288 #else
2289  char yes='1';
2290 #endif /* sun */
2291  struct linger l;
2292 
2293  //int sock_flags;
2294 
2295  /* lose the pesky "Address already in use" error message */
2296  if (setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
2297  err("setsockopt SO_REUSEADDR");
2298  }
2299  l.l_onoff = 1;
2300  l.l_linger = 10;
2301  if (setsockopt(socket,SOL_SOCKET,SO_LINGER,&l,sizeof(l)) == -1) {
2302  perror("setsockopt SO_LINGER");
2303  exit(EXIT_FAILURE);
2304  }
2305  if (setsockopt(socket,SOL_SOCKET,SO_KEEPALIVE,&yes,sizeof(int)) == -1) {
2306  err("setsockopt SO_KEEPALIVE");
2307  }
2308 
2309  /* make the listening socket non-blocking */
2310  /*if ((sock_flags = fcntl(socket, F_GETFL, 0)) == -1) {
2311  err("fcntl F_GETFL");
2312  }
2313  if (fcntl(socket, F_SETFL, sock_flags | O_NONBLOCK) == -1) {
2314  err("fcntl F_SETFL O_NONBLOCK");
2315  }*/
2316 }
2317 
2318 /**
2319  * Connect a server's socket.
2320  *
2321  * @param serve the server we want to connect.
2322  **/
2323 int setup_serve(SERVER *serve) {
2324  struct addrinfo hints;
2325  struct addrinfo *ai = NULL;
2326  gchar *port = NULL;
2327  int e;
2328 
2329  if(!(glob_flags & F_OLDSTYLE)) {
2330  return serve->servename ? 1 : 0;
2331  }
2332  memset(&hints,'\0',sizeof(hints));
2333  hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG | AI_NUMERICSERV;
2334  hints.ai_socktype = SOCK_STREAM;
2335  hints.ai_family = serve->socket_family;
2336 
2337  port = g_strdup_printf ("%d", serve->port);
2338  if (port == NULL)
2339  return 0;
2340 
2341  e = getaddrinfo(serve->listenaddr,port,&hints,&ai);
2342 
2343  g_free(port);
2344 
2345  if(e != 0) {
2346  fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
2347  serve->socket = -1;
2348  freeaddrinfo(ai);
2349  exit(EXIT_FAILURE);
2350  }
2351 
2352  if(serve->socket_family == AF_UNSPEC)
2353  serve->socket_family = ai->ai_family;
2354 
2355 #ifdef WITH_SDP
2356  if ((serve->flags) && F_SDP) {
2357  if (ai->ai_family == AF_INET)
2358  ai->ai_family = AF_INET_SDP;
2359  else (ai->ai_family == AF_INET6)
2360  ai->ai_family = AF_INET6_SDP;
2361  }
2362 #endif
2363  if ((serve->socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0)
2364  err("socket: %m");
2365 
2366  dosockopts(serve->socket);
2367 
2368  DEBUG("Waiting for connections... bind, ");
2369  e = bind(serve->socket, ai->ai_addr, ai->ai_addrlen);
2370  if (e != 0 && errno != EADDRINUSE)
2371  err("bind: %m");
2372  DEBUG("listen, ");
2373  if (listen(serve->socket, 1) < 0)
2374  err("listen: %m");
2375 
2376  freeaddrinfo (ai);
2377  if(serve->servename) {
2378  return 1;
2379  } else {
2380  return 0;
2381  }
2382 }
2383 
2384 void open_modern(void) {
2385  struct addrinfo hints;
2386  struct addrinfo* ai = NULL;
2387  struct sock_flags;
2388  int e;
2389 
2390  memset(&hints, '\0', sizeof(hints));
2391  hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
2392  hints.ai_socktype = SOCK_STREAM;
2393  hints.ai_family = AF_UNSPEC;
2394  hints.ai_protocol = IPPROTO_TCP;
2395  e = getaddrinfo(modern_listen, modernport, &hints, &ai);
2396  if(e != 0) {
2397  fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
2398  exit(EXIT_FAILURE);
2399  }
2400  if((modernsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))<0) {
2401  err("socket: %m");
2402  }
2403 
2405 
2406  if(bind(modernsock, ai->ai_addr, ai->ai_addrlen)) {
2407  err("bind: %m");
2408  }
2409  if(listen(modernsock, 10) <0) {
2410  err("listen: %m");
2411  }
2412 
2413  freeaddrinfo(ai);
2414 }
2415 
2416 /**
2417  * Connect our servers.
2418  **/
2419 void setup_servers(GArray* servers) {
2420  int i;
2421  struct sigaction sa;
2422  int want_modern=0;
2423 
2424  for(i=0;i<servers->len;i++) {
2425  want_modern |= setup_serve(&(g_array_index(servers, SERVER, i)));
2426  }
2427  if(want_modern) {
2428  open_modern();
2429  }
2430  children=g_hash_table_new_full(g_int_hash, g_int_equal, NULL, destroy_pid_t);
2431 
2432  sa.sa_handler = sigchld_handler;
2433  sigemptyset(&sa.sa_mask);
2434  sa.sa_flags = SA_RESTART;
2435  if(sigaction(SIGCHLD, &sa, NULL) == -1)
2436  err("sigaction: %m");
2437  sa.sa_handler = sigterm_handler;
2438  sigemptyset(&sa.sa_mask);
2439  sa.sa_flags = SA_RESTART;
2440  if(sigaction(SIGTERM, &sa, NULL) == -1)
2441  err("sigaction: %m");
2442 }
2443 
2444 /**
2445  * Go daemon (unless we specified at compile time that we didn't want this)
2446  * @param serve the first server of our configuration. If its port is zero,
2447  * then do not daemonize, because we're doing inetd then. This parameter
2448  * is only used to create a PID file of the form
2449  * /var/run/nbd-server.&lt;port&gt;.pid; it's not modified in any way.
2450  **/
2451 #if !defined(NODAEMON)
2452 void daemonize(SERVER* serve) {
2453  FILE*pidf;
2454 
2455  if(serve && !(serve->port)) {
2456  return;
2457  }
2458  if(daemon(0,0)<0) {
2459  err("daemon");
2460  }
2461  if(!*pidftemplate) {
2462  if(serve) {
2463  strncpy(pidftemplate, "/var/run/nbd-server.%d.pid", 255);
2464  } else {
2465  strncpy(pidftemplate, "/var/run/nbd-server.pid", 255);
2466  }
2467  }
2468  snprintf(pidfname, 255, pidftemplate, serve ? serve->port : 0);
2469  pidf=fopen(pidfname, "w");
2470  if(pidf) {
2471  fprintf(pidf,"%d\n", (int)getpid());
2472  fclose(pidf);
2473  } else {
2474  perror("fopen");
2475  fprintf(stderr, "Not fatal; continuing");
2476  }
2477 }
2478 #else
2479 #define daemonize(serve)
2480 #endif /* !defined(NODAEMON) */
2481 
2482 /*
2483  * Everything beyond this point (in the file) is run in non-daemon mode.
2484  * The stuff above daemonize() isn't.
2485  */
2486 
2487 void serve_err(SERVER* serve, const char* msg) G_GNUC_NORETURN;
2488 
2489 void serve_err(SERVER* serve, const char* msg) {
2490  g_message("Export of %s on port %d failed:", serve->exportname,
2491  serve->port);
2492  err(msg);
2493 }
2494 
2495 /**
2496  * Set up user-ID and/or group-ID
2497  **/
2498 void dousers(void) {
2499  struct passwd *pw;
2500  struct group *gr;
2501  gchar* str;
2502  if(rungroup) {
2503  gr=getgrnam(rungroup);
2504  if(!gr) {
2505  str = g_strdup_printf("Invalid group name: %s", rungroup);
2506  err(str);
2507  }
2508  if(setgid(gr->gr_gid)<0) {
2509  err("Could not set GID: %m");
2510  }
2511  }
2512  if(runuser) {
2513  pw=getpwnam(runuser);
2514  if(!pw) {
2515  str = g_strdup_printf("Invalid user name: %s", runuser);
2516  err(str);
2517  }
2518  if(setuid(pw->pw_uid)<0) {
2519  err("Could not set UID: %m");
2520  }
2521  }
2522 }
2523 
2524 #ifndef ISSERVER
2525 void glib_message_syslog_redirect(const gchar *log_domain,
2526  GLogLevelFlags log_level,
2527  const gchar *message,
2528  gpointer user_data)
2529 {
2530  int level=LOG_DEBUG;
2531 
2532  switch( log_level )
2533  {
2534  case G_LOG_FLAG_FATAL:
2535  case G_LOG_LEVEL_CRITICAL:
2536  case G_LOG_LEVEL_ERROR:
2537  level=LOG_ERR;
2538  break;
2539  case G_LOG_LEVEL_WARNING:
2540  level=LOG_WARNING;
2541  break;
2542  case G_LOG_LEVEL_MESSAGE:
2543  case G_LOG_LEVEL_INFO:
2544  level=LOG_INFO;
2545  break;
2546  case G_LOG_LEVEL_DEBUG:
2547  level=LOG_DEBUG;
2548  break;
2549  default:
2550  level=LOG_ERR;
2551  }
2552  syslog(level, "%s", message);
2553 }
2554 #endif
2555 
2556 /**
2557  * Main entry point...
2558  **/
2559 int main(int argc, char *argv[]) {
2560  SERVER *serve;
2561  GArray *servers;
2562  GError *err=NULL;
2563 
2564  if (sizeof( struct nbd_request )!=28) {
2565  fprintf(stderr,"Bad size of structure. Alignment problems?\n");
2566  exit(EXIT_FAILURE) ;
2567  }
2568 
2569  memset(pidftemplate, '\0', 256);
2570 
2571  logging();
2572  config_file_pos = g_strdup(CFILE);
2573  serve=cmdline(argc, argv);
2574  servers = parse_cfile(config_file_pos, TRUE, &err);
2575 
2576  if(serve) {
2577  serve->socket_family = AF_UNSPEC;
2578 
2579  append_serve(serve, servers);
2580 
2581  if (!(serve->port)) {
2582  CLIENT *client;
2583 #ifndef ISSERVER
2584  /* You really should define ISSERVER if you're going to use
2585  * inetd mode, but if you don't, closing stdout and stderr
2586  * (which inetd had connected to the client socket) will let it
2587  * work. */
2588  close(1);
2589  close(2);
2590  open("/dev/null", O_WRONLY);
2591  open("/dev/null", O_WRONLY);
2592  g_log_set_default_handler( glib_message_syslog_redirect, NULL );
2593 #endif
2594  client=g_malloc(sizeof(CLIENT));
2595  client->server=serve;
2596  client->net=0;
2597  client->exportsize=OFFT_MAX;
2598  set_peername(0,client);
2599  serveconnection(client);
2600  return 0;
2601  }
2602  }
2603 
2604  if(!servers || !servers->len) {
2605  if(err && !(err->domain == g_quark_from_string("parse_cfile")
2606  && err->code == CFILE_NOTFOUND)) {
2607  g_warning("Could not parse config file: %s",
2608  err ? err->message : "Unknown error");
2609  }
2610  }
2611  if(serve) {
2612  g_warning("Specifying an export on the command line is deprecated.");
2613  g_warning("Please use a configuration file instead.");
2614  }
2615 
2616  if((!serve) && (!servers||!servers->len)) {
2617  g_message("No configured exports; quitting.");
2618  exit(EXIT_FAILURE);
2619  }
2620  if (!dontfork)
2621  daemonize(serve);
2622  setup_servers(servers);
2623  dousers();
2624  serveloop(servers);
2625  return 0 ;
2626 }