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