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_sighup_caught; /**< Flag set by SIGHUP
181  handler to mark a
182  reconfiguration
183  request */
184 
185 GArray* modernsocks; /**< Sockets for the modern handler. Not used
186  if a client was only specified on the
187  command line; only port used if
188  oldstyle is set to false (and then the
189  command-line client isn't used, gna gna).
190  This may be more than one socket on
191  systems that don't support serving IPv4
192  and IPv6 from the same socket (like,
193  e.g., FreeBSD) */
194 
195 bool logged_oversized=false; /**< whether we logged oversized requests already */
196 
197 /**
198  * Types of virtuatlization
199  **/
200 typedef enum {
201  VIRT_NONE=0, /**< No virtualization */
202  VIRT_IPLIT, /**< Literal IP address as part of the filename */
203  VIRT_IPHASH, /**< Replacing all dots in an ip address by a / before
204  doing the same as in IPLIT */
205  VIRT_CIDR, /**< Every subnet in its own directory */
206 } VIRT_STYLE;
208 /**
209  * Variables associated with a server.
210  **/
211 typedef struct {
212  gchar* exportname; /**< (unprocessed) filename of the file we're exporting */
213  off_t expected_size; /**< size of the exported file as it was told to
214  us through configuration */
215  gchar* listenaddr; /**< The IP address we're listening on */
216  unsigned int port; /**< port we're exporting this file at */
217  char* authname; /**< filename of the authorization file */
218  int flags; /**< flags associated with this exported file */
219  int socket; /**< The socket of this server. */
220  int socket_family; /**< family of the socket */
221  VIRT_STYLE virtstyle;/**< The style of virtualization, if any */
222  uint8_t cidrlen; /**< The length of the mask when we use
223  CIDR-style virtualization */
224  gchar* prerun; /**< command to be ran after connecting a client,
225  but before starting to serve */
226  gchar* postrun; /**< command that will be ran after the client
227  disconnects */
228  gchar* servename; /**< name of the export as selected by nbd-client */
229  int max_connections; /**< maximum number of opened connections */
230  gchar* transactionlog;/**< filename for transaction log */
233 /**
234  * Variables associated with a client socket.
235  **/
236 typedef struct {
237  int fhandle; /**< file descriptor */
238  off_t startoff; /**< starting offset of this file */
241 typedef struct {
242  off_t exportsize; /**< size of the file we're exporting */
243  char *clientname; /**< peer */
244  char *exportname; /**< (processed) filename of the file we're exporting */
245  GArray *export; /**< array of FILE_INFO of exported files;
246  array size is always 1 unless we're
247  doing the multiple file option */
248  int net; /**< The actual client socket */
249  SERVER *server; /**< The server this client is getting data from */
250  char* difffilename; /**< filename of the copy-on-write file, if any */
251  int difffile; /**< filedescriptor of copyonwrite file. @todo
252  shouldn't this be an array too? (cfr export) Or
253  make -m and -c mutually exclusive */
254  u32 difffilelen; /**< number of pages in difffile */
255  u32 *difmap; /**< see comment on the global difmap for this one */
256  gboolean modern; /**< client was negotiated using modern negotiation protocol */
257  int transactionlogfd;/**< fd for transaction log */
258  int clientfeats; /**< Features supported by this client */
261 /**
262  * Type of configuration file values
263  **/
264 typedef enum {
265  PARAM_INT, /**< This parameter is an integer */
266  PARAM_INT64, /**< This parameter is an integer */
267  PARAM_STRING, /**< This parameter is a string */
268  PARAM_BOOL, /**< This parameter is a boolean */
271 /**
272  * Configuration file values
273  **/
274 typedef struct {
275  gchar *paramname; /**< Name of the parameter, as it appears in
276  the config file */
277  gboolean required; /**< Whether this is a required (as opposed to
278  optional) parameter */
279  PARAM_TYPE ptype; /**< Type of the parameter. */
280  gpointer target; /**< Pointer to where the data of this
281  parameter should be written. If ptype is
282  PARAM_BOOL, the data is or'ed rather than
283  overwritten. */
284  gint flagval; /**< Flag mask for this parameter in case ptype
285  is PARAM_BOOL. */
287 
288 /**
289  * Configuration file values of the "generic" section
290  **/
291 struct generic_conf {
292  gchar *user; /**< user we run the server as */
293  gchar *group; /**< group we run running as */
294  gchar *modernaddr; /**< address of the modern socket */
295  gchar *modernport; /**< port of the modern socket */
296  gint flags; /**< global flags */
297 };
299 /**
300  * Translate a command name into human readable form
301  *
302  * @param command The command number (after applying NBD_CMD_MASK_COMMAND)
303  * @return pointer to the command name
304  **/
305 static inline const char * getcommandname(uint64_t command) {
306  switch (command) {
308  return "NBD_CMD_READ";
309  case NBD_CMD_WRITE:
310  return "NBD_CMD_WRITE";
311  case NBD_CMD_DISC:
312  return "NBD_CMD_DISC";
313  case NBD_CMD_FLUSH:
314  return "NBD_CMD_FLUSH";
315  case NBD_CMD_TRIM:
316  return "NBD_CMD_TRIM";
317  default:
318  return "UNKNOWN";
319  }
320 }
321 
322 /**
323  * Check whether a client is allowed to connect. Works with an authorization
324  * file which contains one line per machine, no wildcards.
325  *
326  * @param opts The client who's trying to connect.
327  * @return 0 - authorization refused, 1 - OK
328  **/
329 int authorized_client(CLIENT *opts) {
330  const char *ERRMSG="Invalid entry '%s' in authfile '%s', so, refusing all connections.";
331  FILE *f ;
332  char line[LINELEN];
333  char *tmp;
334  struct in_addr addr;
335  struct in_addr client;
336  struct in_addr cltemp;
337  int len;
338 
339  if ((f=fopen(opts->server->authname,"r"))==NULL) {
340  msg(LOG_INFO, "Can't open authorization file %s (%s).",
341  opts->server->authname, strerror(errno));
342  return 1 ;
343  }
344 
345  inet_aton(opts->clientname, &client);
346  while (fgets(line,LINELEN,f)!=NULL) {
347  if((tmp=strchr(line, '/'))) {
348  if(strlen(line)<=tmp-line) {
349  msg(LOG_CRIT, ERRMSG, line, opts->server->authname);
350  return 0;
351  }
352  *(tmp++)=0;
353  if(!inet_aton(line,&addr)) {
354  msg(LOG_CRIT, ERRMSG, line, opts->server->authname);
355  return 0;
356  }
357  len=strtol(tmp, NULL, 0);
358  addr.s_addr>>=32-len;
359  addr.s_addr<<=32-len;
360  memcpy(&cltemp,&client,sizeof(client));
361  cltemp.s_addr>>=32-len;
362  cltemp.s_addr<<=32-len;
363  if(addr.s_addr == cltemp.s_addr) {
364  return 1;
365  }
366  }
367  if (strncmp(line,opts->clientname,strlen(opts->clientname))==0) {
368  fclose(f);
369  return 1;
370  }
371  }
372  fclose(f);
373  return 0;
374 }
375 
376 /**
377  * Read data from a file descriptor into a buffer
378  *
379  * @param f a file descriptor
380  * @param buf a buffer
381  * @param len the number of bytes to be read
382  **/
383 static inline void readit(int f, void *buf, size_t len) {
384  ssize_t res;
385  while (len > 0) {
386  DEBUG("*");
387  if ((res = read(f, buf, len)) <= 0) {
388  if(errno != EAGAIN) {
389  err("Read failed: %m");
390  }
391  } else {
392  len -= res;
393  buf += res;
394  }
395  }
396 }
397 
398 /**
399  * Consume data from an FD that we don't want
400  *
401  * @param f a file descriptor
402  * @param buf a buffer
403  * @param len the number of bytes to consume
404  * @param bufsiz the size of the buffer
405  **/
406 static inline void consume(int f, void * buf, size_t len, size_t bufsiz) {
407  size_t curlen;
408  while (len>0) {
409  curlen = (len>bufsiz)?bufsiz:len;
410  readit(f, buf, curlen);
411  len -= curlen;
412  }
413 }
414 
415 
416 /**
417  * Write data from a buffer into a filedescriptor
418  *
419  * @param f a file descriptor
420  * @param buf a buffer containing data
421  * @param len the number of bytes to be written
422  **/
423 static inline void writeit(int f, void *buf, size_t len) {
424  ssize_t res;
425  while (len > 0) {
426  DEBUG("+");
427  if ((res = write(f, buf, len)) <= 0)
428  err("Send failed: %m");
429  len -= res;
430  buf += res;
431  }
432 }
433 
434 /**
435  * Print out a message about how to use nbd-server. Split out to a separate
436  * function so that we can call it from multiple places
437  */
438 void usage() {
439  printf("This is nbd-server version " VERSION "\n");
440  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"
441  "\t-r|--read-only\t\tread only\n"
442  "\t-m|--multi-file\t\tmultiple file\n"
443  "\t-c|--copy-on-write\tcopy on write\n"
444  "\t-C|--config-file\tspecify an alternate configuration file\n"
445  "\t-l|--authorize-file\tfile with list of hosts that are allowed to\n\t\t\t\tconnect.\n"
446  "\t-p|--pid-file\t\tspecify a filename to write our PID to\n"
447  "\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"
448  "\t-M|--max-connections\tspecify the maximum number of opened connections\n\n"
449  "\tif port is set to 0, stdin is used (for running from inetd).\n"
450  "\tif file_to_export contains '%%s', it is substituted with the IP\n"
451  "\t\taddress of the machine trying to connect\n"
452  "\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");
453  printf("Using configuration file %s\n", CFILE);
454 }
455 
456 /* Dumps a config file section of the given SERVER*, and exits. */
457 void dump_section(SERVER* serve, gchar* section_header) {
458  printf("[%s]\n", section_header);
459  printf("\texportname = %s\n", serve->exportname);
460  printf("\tlistenaddr = %s\n", serve->listenaddr);
461  printf("\tport = %d\n", serve->port);
462  if(serve->flags & F_READONLY) {
463  printf("\treadonly = true\n");
464  }
465  if(serve->flags & F_MULTIFILE) {
466  printf("\tmultifile = true\n");
467  }
468  if(serve->flags & F_COPYONWRITE) {
469  printf("\tcopyonwrite = true\n");
470  }
471  if(serve->expected_size) {
472  printf("\tfilesize = %lld\n", (long long int)serve->expected_size);
473  }
474  if(serve->authname) {
475  printf("\tauthfile = %s\n", serve->authname);
476  }
477  exit(EXIT_SUCCESS);
478 }
479 
480 /**
481  * Parse the command line.
482  *
483  * @param argc the argc argument to main()
484  * @param argv the argv argument to main()
485  **/
486 SERVER* cmdline(int argc, char *argv[]) {
487  int i=0;
488  int nonspecial=0;
489  int c;
490  struct option long_options[] = {
491  {"read-only", no_argument, NULL, 'r'},
492  {"multi-file", no_argument, NULL, 'm'},
493  {"copy-on-write", no_argument, NULL, 'c'},
494  {"dont-fork", no_argument, NULL, 'd'},
495  {"authorize-file", required_argument, NULL, 'l'},
496  {"config-file", required_argument, NULL, 'C'},
497  {"pid-file", required_argument, NULL, 'p'},
498  {"output-config", required_argument, NULL, 'o'},
499  {"max-connection", required_argument, NULL, 'M'},
500  {0,0,0,0}
501  };
502  SERVER *serve;
503  off_t es;
504  size_t last;
505  char suffix;
506  gboolean do_output=FALSE;
507  gchar* section_header="";
508  gchar** addr_port;
509 
510  if(argc==1) {
511  return NULL;
512  }
513  serve=g_new0(SERVER, 1);
514  serve->authname = g_strdup(default_authname);
515  serve->virtstyle=VIRT_IPLIT;
516  while((c=getopt_long(argc, argv, "-C:cdl:mo:rp:M:", long_options, &i))>=0) {
517  switch (c) {
518  case 1:
519  /* non-option argument */
520  switch(nonspecial++) {
521  case 0:
522  if(strchr(optarg, ':') == strrchr(optarg, ':')) {
523  addr_port=g_strsplit(optarg, ":", 2);
524 
525  /* Check for "@" - maybe user using this separator
526  for IPv4 address */
527  if(!addr_port[1]) {
528  g_strfreev(addr_port);
529  addr_port=g_strsplit(optarg, "@", 2);
530  }
531  } else {
532  addr_port=g_strsplit(optarg, "@", 2);
533  }
534 
535  if(addr_port[1]) {
536  serve->port=strtol(addr_port[1], NULL, 0);
537  serve->listenaddr=g_strdup(addr_port[0]);
538  } else {
539  serve->listenaddr=NULL;
540  serve->port=strtol(addr_port[0], NULL, 0);
541  }
542  g_strfreev(addr_port);
543  break;
544  case 1:
545  serve->exportname = g_strdup(optarg);
546  if(serve->exportname[0] != '/') {
547  fprintf(stderr, "E: The to be exported file needs to be an absolute filename!\n");
548  exit(EXIT_FAILURE);
549  }
550  break;
551  case 2:
552  last=strlen(optarg)-1;
553  suffix=optarg[last];
554  if (suffix == 'k' || suffix == 'K' ||
555  suffix == 'm' || suffix == 'M')
556  optarg[last] = '\0';
557  es = (off_t)atoll(optarg);
558  switch (suffix) {
559  case 'm':
560  case 'M': es <<= 10;
561  case 'k':
562  case 'K': es <<= 10;
563  default : break;
564  }
565  serve->expected_size = es;
566  break;
567  }
568  break;
569  case 'r':
570  serve->flags |= F_READONLY;
571  break;
572  case 'm':
573  serve->flags |= F_MULTIFILE;
574  break;
575  case 'o':
576  do_output = TRUE;
577  section_header = g_strdup(optarg);
578  break;
579  case 'p':
580  strncpy(pidftemplate, optarg, 256);
581  break;
582  case 'c':
583  serve->flags |=F_COPYONWRITE;
584  break;
585  case 'd':
586  dontfork = 1;
587  break;
588  case 'C':
589  g_free(config_file_pos);
590  config_file_pos=g_strdup(optarg);
591  break;
592  case 'l':
593  g_free(serve->authname);
594  serve->authname=g_strdup(optarg);
595  break;
596  case 'M':
597  serve->max_connections = strtol(optarg, NULL, 0);
598  break;
599  default:
600  usage();
601  exit(EXIT_FAILURE);
602  break;
603  }
604  }
605  /* What's left: the port to export, the name of the to be exported
606  * file, and, optionally, the size of the file, in that order. */
607  if(nonspecial<2) {
608  g_free(serve);
609  serve=NULL;
610  } else {
612  }
613  if(do_output) {
614  if(!serve) {
615  g_critical("Need a complete configuration on the command line to output a config file section!");
616  exit(EXIT_FAILURE);
617  }
618  dump_section(serve, section_header);
619  }
620  return serve;
621 }
622 
623 /**
624  * Error domain common for all NBD server errors.
625  **/
626 #define NBDS_ERR g_quark_from_static_string("server-error-quark")
627 
628 /**
629  * NBD server error codes.
630  **/
631 typedef enum {
632  NBDS_ERR_CFILE_NOTFOUND, /**< The configuration file is not found */
633  NBDS_ERR_CFILE_MISSING_GENERIC, /**< The (required) group "generic" is missing */
634  NBDS_ERR_CFILE_KEY_MISSING, /**< A (required) key is missing */
635  NBDS_ERR_CFILE_VALUE_INVALID, /**< A value is syntactically invalid */
636  NBDS_ERR_CFILE_VALUE_UNSUPPORTED, /**< A value is not supported in this build */
637  NBDS_ERR_CFILE_NO_EXPORTS, /**< A config file was specified that does not
638  define any exports */
639  NBDS_ERR_CFILE_INCORRECT_PORT, /**< The reserved port was specified for an
640  old-style export. */
641  NBDS_ERR_CFILE_DIR_UNKNOWN, /**< A directory requested does not exist*/
642  NBDS_ERR_CFILE_READDIR_ERR, /**< Error occurred during readdir() */
643  NBDS_ERR_SO_LINGER, /**< Failed to set SO_LINGER to a socket */
644  NBDS_ERR_SO_REUSEADDR, /**< Failed to set SO_REUSEADDR to a socket */
645  NBDS_ERR_SO_KEEPALIVE, /**< Failed to set SO_KEEPALIVE to a socket */
646  NBDS_ERR_GAI, /**< Failed to get address info */
647  NBDS_ERR_SOCKET, /**< Failed to create a socket */
648  NBDS_ERR_BIND, /**< Failed to bind an address to socket */
649  NBDS_ERR_LISTEN, /**< Failed to start listening on a socket */
650  NBDS_ERR_SYS, /**< Underlying system call or library error */
653 /**
654  * duplicate server
655  * @param s the old server we want to duplicate
656  * @return new duplicated server
657  **/
658 SERVER* dup_serve(const SERVER *const s) {
659  SERVER *serve = NULL;
661  serve=g_new0(SERVER, 1);
662  if(serve == NULL)
663  return NULL;
664 
665  if(s->exportname)
666  serve->exportname = g_strdup(s->exportname);
667 
668  serve->expected_size = s->expected_size;
669 
670  if(s->listenaddr)
671  serve->listenaddr = g_strdup(s->listenaddr);
672 
673  serve->port = s->port;
674 
675  if(s->authname)
676  serve->authname = strdup(s->authname);
677 
678  serve->flags = s->flags;
679  serve->socket = s->socket;
680  serve->socket_family = s->socket_family;
681  serve->virtstyle = s->virtstyle;
682  serve->cidrlen = s->cidrlen;
683 
684  if(s->prerun)
685  serve->prerun = g_strdup(s->prerun);
686 
687  if(s->postrun)
688  serve->postrun = g_strdup(s->postrun);
689 
690  if(s->transactionlog)
691  serve->transactionlog = g_strdup(s->transactionlog);
692 
693  if(s->servename)
694  serve->servename = g_strdup(s->servename);
695 
696  serve->max_connections = s->max_connections;
697 
698  return serve;
699 }
700 
701 /**
702  * append new server to array
703  * @param s server
704  * @param a server array
705  * @return 0 success, -1 error
706  */
707 int append_serve(const SERVER *const s, GArray *const a) {
708  SERVER *ns = NULL;
709  struct addrinfo hints;
710  struct addrinfo *ai = NULL;
711  struct addrinfo *rp = NULL;
712  char host[NI_MAXHOST];
713  gchar *port = NULL;
714  int e;
715  int ret;
716 
717  assert(s != NULL);
718 
719  port = g_strdup_printf("%d", s->port);
720 
721  memset(&hints,'\0',sizeof(hints));
722  hints.ai_family = AF_UNSPEC;
723  hints.ai_socktype = SOCK_STREAM;
724  hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
725  hints.ai_protocol = IPPROTO_TCP;
726 
727  e = getaddrinfo(s->listenaddr, port, &hints, &ai);
728 
729  if (port)
730  g_free(port);
731 
732  if(e == 0) {
733  for (rp = ai; rp != NULL; rp = rp->ai_next) {
734  e = getnameinfo(rp->ai_addr, rp->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
735 
736  if (e != 0) { // error
737  fprintf(stderr, "getnameinfo: %s\n", gai_strerror(e));
738  continue;
739  }
740 
741  // duplicate server and set listenaddr to resolved IP address
742  ns = dup_serve (s);
743  if (ns) {
744  ns->listenaddr = g_strdup(host);
745  ns->socket_family = rp->ai_family;
746  g_array_append_val(a, *ns);
747  free(ns);
748  ns = NULL;
749  }
750  }
751 
752  ret = 0;
753  } else {
754  fprintf(stderr, "getaddrinfo failed on listen host/address: %s (%s)\n", s->listenaddr ? s->listenaddr : "any", gai_strerror(e));
755  ret = -1;
756  }
757 
758  if (ai)
759  freeaddrinfo(ai);
760 
761  return ret;
762 }
763 
764 /* forward definition of parse_cfile */
765 GArray* parse_cfile(gchar* f, struct generic_conf *genconf, GError** e);
766 
767 /**
768  * Parse config file snippets in a directory. Uses readdir() and friends
769  * to find files and open them, then passes them on to parse_cfile
770  * with have_global set false
771  **/
772 GArray* do_cfile_dir(gchar* dir, GError** e) {
773  DIR* dirh = opendir(dir);
774  struct dirent* de;
775  gchar* fname;
776  GArray* retval = NULL;
777  GArray* tmp;
778  struct stat stbuf;
779 
780  if(!dir) {
781  g_set_error(e, NBDS_ERR, NBDS_ERR_CFILE_DIR_UNKNOWN, "Invalid directory specified: %s", strerror(errno));
782  return NULL;
783  }
784  errno=0;
785  while((de = readdir(dirh))) {
786  int saved_errno=errno;
787  fname = g_build_filename(dir, de->d_name, NULL);
788  switch(de->d_type) {
789  case DT_UNKNOWN:
790  /* Filesystem doesn't return type of
791  * file through readdir. Run stat() on
792  * the file instead */
793  if(stat(fname, &stbuf)) {
794  perror("stat");
795  goto err_out;
796  }
797  if (!S_ISREG(stbuf.st_mode)) {
798  goto next;
799  }
800  case DT_REG:
801  /* Skip unless the name ends with '.conf' */
802  if(strcmp((de->d_name + strlen(de->d_name) - 5), ".conf")) {
803  goto next;
804  }
805  tmp = parse_cfile(fname, NULL, e);
806  errno=saved_errno;
807  if(*e) {
808  goto err_out;
809  }
810  if(!retval)
811  retval = g_array_new(FALSE, TRUE, sizeof(SERVER));
812  retval = g_array_append_vals(retval, tmp->data, tmp->len);
813  g_array_free(tmp, TRUE);
814  default:
815  break;
816  }
817  next:
818  g_free(fname);
819  }
820  if(errno) {
821  g_set_error(e, NBDS_ERR, NBDS_ERR_CFILE_READDIR_ERR, "Error trying to read directory: %s", strerror(errno));
822  err_out:
823  if(retval)
824  g_array_free(retval, TRUE);
825  return NULL;
826  }
827  return retval;
828 }
829 
830 /**
831  * Parse the config file.
832  *
833  * @param f the name of the config file
834  *
835  * @param genconf a pointer to generic configuration which will get
836  * updated with parsed values. If NULL, then parsed generic
837  * configuration values are safely and silently discarded.
838  *
839  * @param e a GError. Error code can be any of the following:
840  * NBDS_ERR_CFILE_NOTFOUND, NBDS_ERR_CFILE_MISSING_GENERIC,
841  * NBDS_ERR_CFILE_VALUE_INVALID, NBDS_ERR_CFILE_VALUE_UNSUPPORTED
842  * or NBDS_ERR_CFILE_NO_EXPORTS. @see NBDS_ERRS.
843  *
844  * @return a Array of SERVER* pointers, If the config file is empty or does not
845  * exist, returns an empty GHashTable; if the config file contains an
846  * error, returns NULL, and e is set appropriately
847  **/
848 GArray* parse_cfile(gchar* f, struct generic_conf *const genconf, GError** e) {
849  const char* DEFAULT_ERROR = "Could not parse %s in group %s: %s";
850  const char* MISSING_REQUIRED_ERROR = "Could not find required value %s in group %s: %s";
851  gchar* cfdir = NULL;
852  SERVER s;
853  gchar *virtstyle=NULL;
854  PARAM lp[] = {
855  { "exportname", TRUE, PARAM_STRING, &(s.exportname), 0 },
856  { "port", TRUE, PARAM_INT, &(s.port), 0 },
857  { "authfile", FALSE, PARAM_STRING, &(s.authname), 0 },
858  { "filesize", FALSE, PARAM_OFFT, &(s.expected_size), 0 },
859  { "virtstyle", FALSE, PARAM_STRING, &(virtstyle), 0 },
860  { "prerun", FALSE, PARAM_STRING, &(s.prerun), 0 },
861  { "postrun", FALSE, PARAM_STRING, &(s.postrun), 0 },
862  { "transactionlog", FALSE, PARAM_STRING, &(s.transactionlog), 0 },
863  { "readonly", FALSE, PARAM_BOOL, &(s.flags), F_READONLY },
864  { "multifile", FALSE, PARAM_BOOL, &(s.flags), F_MULTIFILE },
865  { "copyonwrite", FALSE, PARAM_BOOL, &(s.flags), F_COPYONWRITE },
866  { "sparse_cow", FALSE, PARAM_BOOL, &(s.flags), F_SPARSE },
867  { "sdp", FALSE, PARAM_BOOL, &(s.flags), F_SDP },
868  { "sync", FALSE, PARAM_BOOL, &(s.flags), F_SYNC },
869  { "flush", FALSE, PARAM_BOOL, &(s.flags), F_FLUSH },
870  { "fua", FALSE, PARAM_BOOL, &(s.flags), F_FUA },
871  { "rotational", FALSE, PARAM_BOOL, &(s.flags), F_ROTATIONAL },
872  { "temporary", FALSE, PARAM_BOOL, &(s.flags), F_TEMPORARY },
873  { "trim", FALSE, PARAM_BOOL, &(s.flags), F_TRIM },
874  { "listenaddr", FALSE, PARAM_STRING, &(s.listenaddr), 0 },
875  { "maxconnections", FALSE, PARAM_INT, &(s.max_connections), 0 },
876  };
877  const int lp_size=sizeof(lp)/sizeof(PARAM);
878  struct generic_conf genconftmp;
879  PARAM gp[] = {
880  { "user", FALSE, PARAM_STRING, &(genconftmp.user), 0 },
881  { "group", FALSE, PARAM_STRING, &(genconftmp.group), 0 },
882  { "oldstyle", FALSE, PARAM_BOOL, &(genconftmp.flags), F_OLDSTYLE },
883  { "listenaddr", FALSE, PARAM_STRING, &(genconftmp.modernaddr), 0 },
884  { "port", FALSE, PARAM_STRING, &(genconftmp.modernport), 0 },
885  { "includedir", FALSE, PARAM_STRING, &cfdir, 0 },
886  { "allowlist", FALSE, PARAM_BOOL, &(genconftmp.flags), F_LIST },
887  };
888  PARAM* p=gp;
889  int p_size=sizeof(gp)/sizeof(PARAM);
890  GKeyFile *cfile;
891  GError *err = NULL;
892  const char *err_msg=NULL;
893  GArray *retval=NULL;
894  gchar **groups;
895  gboolean bval;
896  gint ival;
897  gint64 i64val;
898  gchar* sval;
899  gchar* startgroup;
900  gint i;
901  gint j;
902 
903  memset(&genconftmp, 0, sizeof(struct generic_conf));
904 
905  if (genconf) {
906  /* Use the passed configuration values as defaults. The
907  * parsing algorithm below updates all parameter targets
908  * found from configuration files. */
909  memcpy(&genconftmp, genconf, sizeof(struct generic_conf));
910  }
911 
912  cfile = g_key_file_new();
913  retval = g_array_new(FALSE, TRUE, sizeof(SERVER));
914  if(!g_key_file_load_from_file(cfile, f, G_KEY_FILE_KEEP_COMMENTS |
915  G_KEY_FILE_KEEP_TRANSLATIONS, &err)) {
916  g_set_error(e, NBDS_ERR, NBDS_ERR_CFILE_NOTFOUND, "Could not open config file %s: %s",
917  f, err->message);
918  g_key_file_free(cfile);
919  return retval;
920  }
921  startgroup = g_key_file_get_start_group(cfile);
922  if((!startgroup || strcmp(startgroup, "generic")) && genconf) {
923  g_set_error(e, NBDS_ERR, NBDS_ERR_CFILE_MISSING_GENERIC, "Config file does not contain the [generic] group!");
924  g_key_file_free(cfile);
925  return NULL;
926  }
927  groups = g_key_file_get_groups(cfile, NULL);
928  for(i=0;groups[i];i++) {
929  memset(&s, '\0', sizeof(SERVER));
930 
931  /* After the [generic] group or when we're parsing an include
932  * directory, start parsing exports */
933  if(i==1 || !genconf) {
934  p=lp;
935  p_size=lp_size;
936  if(!(glob_flags & F_OLDSTYLE)) {
937  lp[1].required = FALSE;
938  }
939  }
940  for(j=0;j<p_size;j++) {
941  assert(p[j].target != NULL);
942  assert(p[j].ptype==PARAM_INT||p[j].ptype==PARAM_STRING||p[j].ptype==PARAM_BOOL||p[j].ptype==PARAM_INT64);
943  switch(p[j].ptype) {
944  case PARAM_INT:
945  ival = g_key_file_get_integer(cfile,
946  groups[i],
947  p[j].paramname,
948  &err);
949  if(!err) {
950  *((gint*)p[j].target) = ival;
951  }
952  break;
953  case PARAM_INT64:
954  i64val = g_key_file_get_int64(cfile,
955  groups[i],
956  p[j].paramname,
957  &err);
958  if(!err) {
959  *((gint64*)p[j].target) = i64val;
960  }
961  break;
962  case PARAM_STRING:
963  sval = g_key_file_get_string(cfile,
964  groups[i],
965  p[j].paramname,
966  &err);
967  if(!err) {
968  *((gchar**)p[j].target) = sval;
969  }
970  break;
971  case PARAM_BOOL:
972  bval = g_key_file_get_boolean(cfile,
973  groups[i],
974  p[j].paramname, &err);
975  if(!err) {
976  if(bval) {
977  *((gint*)p[j].target) |= p[j].flagval;
978  } else {
979  *((gint*)p[j].target) &= ~(p[j].flagval);
980  }
981  }
982  break;
983  }
984  if(err) {
985  if(err->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
986  if(!p[j].required) {
987  /* Ignore not-found error for optional values */
988  g_clear_error(&err);
989  continue;
990  } else {
991  err_msg = MISSING_REQUIRED_ERROR;
992  }
993  } else {
994  err_msg = DEFAULT_ERROR;
995  }
996  g_set_error(e, NBDS_ERR, NBDS_ERR_CFILE_VALUE_INVALID, err_msg, p[j].paramname, groups[i], err->message);
997  g_array_free(retval, TRUE);
998  g_error_free(err);
999  g_key_file_free(cfile);
1000  return NULL;
1001  }
1002  }
1003  if(virtstyle) {
1004  if(!strncmp(virtstyle, "none", 4)) {
1005  s.virtstyle=VIRT_NONE;
1006  } else if(!strncmp(virtstyle, "ipliteral", 9)) {
1008  } else if(!strncmp(virtstyle, "iphash", 6)) {
1010  } else if(!strncmp(virtstyle, "cidrhash", 8)) {
1011  s.virtstyle=VIRT_CIDR;
1012  if(strlen(virtstyle)<10) {
1013  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]);
1014  g_array_free(retval, TRUE);
1015  g_key_file_free(cfile);
1016  return NULL;
1017  }
1018  s.cidrlen=strtol(virtstyle+8, NULL, 0);
1019  } else {
1020  g_set_error(e, NBDS_ERR, NBDS_ERR_CFILE_VALUE_INVALID, "Invalid value %s for parameter virtstyle in group %s", virtstyle, groups[i]);
1021  g_array_free(retval, TRUE);
1022  g_key_file_free(cfile);
1023  return NULL;
1024  }
1025  } else {
1027  }
1028  if(s.port && !(glob_flags & F_OLDSTYLE)) {
1029  g_warning("A port was specified, but oldstyle exports were not requested. This may not do what you expect.");
1030  g_warning("Please read 'man 5 nbd-server' and search for oldstyle for more info");
1031  }
1032  /* Don't need to free this, it's not our string */
1033  virtstyle=NULL;
1034  /* Don't append values for the [generic] group */
1035  if(i>0 || !genconf) {
1036  s.socket_family = AF_UNSPEC;
1037  s.servename = groups[i];
1038 
1039  append_serve(&s, retval);
1040  }
1041 #ifndef WITH_SDP
1042  if(s.flags & F_SDP) {
1043  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]);
1044  g_array_free(retval, TRUE);
1045  g_key_file_free(cfile);
1046  return NULL;
1047  }
1048 #endif
1049  }
1050  g_key_file_free(cfile);
1051  if(cfdir) {
1052  GArray* extra = do_cfile_dir(cfdir, e);
1053  if(extra) {
1054  retval = g_array_append_vals(retval, extra->data, extra->len);
1055  i+=extra->len;
1056  g_array_free(extra, TRUE);
1057  } else {
1058  if(*e) {
1059  g_array_free(retval, TRUE);
1060  return NULL;
1061  }
1062  }
1063  }
1064  if(i==1 && genconf) {
1065  g_set_error(e, NBDS_ERR, NBDS_ERR_CFILE_NO_EXPORTS, "The config file does not specify any exports");
1066  }
1067 
1068  if (genconf) {
1069  /* Return the updated generic configuration through the
1070  * pointer parameter. */
1071  memcpy(genconf, &genconftmp, sizeof(struct generic_conf));
1072  }
1073 
1074  return retval;
1075 }
1076 
1077 /**
1078  * Signal handler for SIGCHLD
1079  * @param s the signal we're handling (must be SIGCHLD, or something
1080  * is severely wrong)
1081  **/
1082 void sigchld_handler(int s) {
1083  int status;
1084  int* i;
1085  pid_t pid;
1086 
1087  while((pid=waitpid(-1, &status, WNOHANG)) > 0) {
1088  if(WIFEXITED(status)) {
1089  msg(LOG_INFO, "Child exited with %d", WEXITSTATUS(status));
1090  }
1091  i=g_hash_table_lookup(children, &pid);
1092  if(!i) {
1093  msg(LOG_INFO, "SIGCHLD received for an unknown child with PID %ld", (long)pid);
1094  } else {
1095  DEBUG("Removing %d from the list of children", pid);
1096  g_hash_table_remove(children, &pid);
1097  }
1098  }
1099 }
1100 
1101 /**
1102  * Kill a child. Called from sigterm_handler::g_hash_table_foreach.
1103  *
1104  * @param key the key
1105  * @param value the value corresponding to the above key
1106  * @param user_data a pointer which we always set to 1, so that we know what
1107  * will happen next.
1108  **/
1109 void killchild(gpointer key, gpointer value, gpointer user_data) {
1110  pid_t *pid=value;
1112  kill(*pid, SIGTERM);
1113 }
1114 
1115 /**
1116  * Handle SIGTERM and dispatch it to our children
1117  * @param s the signal we're handling (must be SIGTERM, or something
1118  * is severely wrong).
1119  **/
1120 void sigterm_handler(int s) {
1121  g_hash_table_foreach(children, killchild, NULL);
1122  unlink(pidfname);
1123 
1124  exit(EXIT_SUCCESS);
1125 }
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 void
2202 handle_connection(GArray *servers, int net, SERVER *serve, CLIENT *client)
2203 {
2204  int sock_flags_old;
2205  int sock_flags_new;
2206 
2207  if(serve->max_connections > 0 &&
2208  g_hash_table_size(children) >= serve->max_connections) {
2209  msg(LOG_INFO, "Max connections reached");
2210  goto handle_connection_out;
2211  }
2212  if((sock_flags_old = fcntl(net, F_GETFL, 0)) == -1) {
2213  err("fcntl F_GETFL");
2214  }
2215  sock_flags_new = sock_flags_old & ~O_NONBLOCK;
2216  if (sock_flags_new != sock_flags_old &&
2217  fcntl(net, F_SETFL, sock_flags_new) == -1) {
2218  err("fcntl F_SETFL ~O_NONBLOCK");
2219  }
2220  if(!client) {
2221  client = g_new0(CLIENT, 1);
2222  client->server=serve;
2223  client->exportsize=OFFT_MAX;
2224  client->net=net;
2225  client->transactionlogfd = -1;
2226  }
2227  if (set_peername(net, client)) {
2228  goto handle_connection_out;
2229  }
2230  if (!authorized_client(client)) {
2231  msg(LOG_INFO, "Unauthorized client");
2232  goto handle_connection_out;
2233  }
2234  msg(LOG_INFO, "Authorized client");
2235 
2236  if (!dontfork) {
2237  pid_t pid;
2238  int i;
2239  sigset_t newset;
2240  sigset_t oldset;
2241 
2242  sigemptyset(&newset);
2243  sigaddset(&newset, SIGCHLD);
2244  sigaddset(&newset, SIGTERM);
2245  sigprocmask(SIG_BLOCK, &newset, &oldset);
2246  if ((pid = fork()) < 0) {
2247  msg(LOG_INFO, "Could not fork (%s)", strerror(errno));
2248  sigprocmask(SIG_SETMASK, &oldset, NULL);
2249  goto handle_connection_out;
2250  }
2251  if (pid > 0) { /* parent */
2252  pid_t *pidp;
2253 
2254  pidp = g_malloc(sizeof(pid_t));
2255  *pidp = pid;
2256  g_hash_table_insert(children, pidp, pidp);
2257  sigprocmask(SIG_SETMASK, &oldset, NULL);
2258  goto handle_connection_out;
2259  }
2260  /* child */
2261  signal(SIGCHLD, SIG_DFL);
2262  signal(SIGTERM, SIG_DFL);
2263  signal(SIGHUP, SIG_DFL);
2264  sigprocmask(SIG_SETMASK, &oldset, NULL);
2265 
2266  g_hash_table_destroy(children);
2267  children = NULL;
2268  for(i=0;i<servers->len;i++) {
2269  serve=&g_array_index(servers, SERVER, i);
2270  close(serve->socket);
2271  }
2272  /* FALSE does not free the
2273  actual data. This is required,
2274  because the client has a
2275  direct reference into that
2276  data, and otherwise we get a
2277  segfault... */
2278  g_array_free(servers, FALSE);
2279  for(i=0;i<modernsocks->len;i++) {
2280  close(g_array_index(modernsocks, int, i));
2281  }
2282  g_array_free(modernsocks, TRUE);
2283  }
2284 
2285  msg(LOG_INFO, "Starting to serve");
2286  serveconnection(client);
2287  exit(EXIT_SUCCESS);
2288 
2289 handle_connection_out:
2290  g_free(client);
2291  close(net);
2292 }
2293 
2294 /**
2295  * Return the index of the server whose servename matches the given
2296  * name.
2297  *
2298  * @param servename a string to match
2299  * @param servers an array of servers
2300  * @return the first index of the server whose servename matches the
2301  * given name or -1 if one cannot be found
2302  **/
2303 static int get_index_by_servename(const gchar *const servename,
2304  const GArray *const servers) {
2305  int i;
2306 
2307  for (i = 0; i < servers->len; ++i) {
2308  const SERVER server = g_array_index(servers, SERVER, i);
2309 
2310  if (strcmp(servename, server.servename) == 0)
2311  return i;
2312  }
2313 
2314  return -1;
2315 }
2316 
2317 int setup_serve(SERVER *const serve, GError **const gerror);
2318 
2319 /**
2320  * Parse configuration files and add servers to the array if they don't
2321  * already exist there. The existence is tested by comparing
2322  * servenames. A server is appended to the array only if its servename
2323  * is unique among all other servers.
2324  *
2325  * @param servers an array of servers
2326  * @return the number of new servers appended to the array, or -1 in
2327  * case of an error
2328  **/
2329 static int append_new_servers(GArray *const servers, GError **const gerror) {
2330  int i;
2331  GArray *new_servers;
2332  const int old_len = servers->len;
2333  int retval = -1;
2334  struct generic_conf genconf;
2335 
2336  new_servers = parse_cfile(config_file_pos, &genconf, gerror);
2337  if (!new_servers)
2338  goto out;
2339 
2340  for (i = 0; i < new_servers->len; ++i) {
2341  SERVER new_server = g_array_index(new_servers, SERVER, i);
2342 
2343  if (new_server.servename
2344  && -1 == get_index_by_servename(new_server.servename,
2345  servers)) {
2346  if (setup_serve(&new_server, gerror) == -1)
2347  goto out;
2348  if (append_serve(&new_server, servers) == -1)
2349  goto out;
2350  }
2351  }
2352 
2353  retval = servers->len - old_len;
2354 out:
2355  g_array_free(new_servers, TRUE);
2356 
2357  return retval;
2358 }
2359 
2360 /**
2361  * Loop through the available servers, and serve them. Never returns.
2362  **/
2363 void serveloop(GArray* servers) {
2364  struct sockaddr_storage addrin;
2365  socklen_t addrinlen=sizeof(addrin);
2366  int i;
2367  int max;
2368  int sock;
2369  fd_set mset;
2370  fd_set rset;
2371 
2372  /*
2373  * Set up the master fd_set. The set of descriptors we need
2374  * to select() for never changes anyway and it buys us a *lot*
2375  * of time to only build this once. However, if we ever choose
2376  * to not fork() for clients anymore, we may have to revisit
2377  * this.
2378  */
2379  max=0;
2380  FD_ZERO(&mset);
2381  for(i=0;i<servers->len;i++) {
2382  if((sock=(g_array_index(servers, SERVER, i)).socket) >= 0) {
2383  FD_SET(sock, &mset);
2384  max=sock>max?sock:max;
2385  }
2386  }
2387  for(i=0;i<modernsocks->len;i++) {
2388  int sock = g_array_index(modernsocks, int, i);
2389  FD_SET(sock, &mset);
2390  max=sock>max?sock:max;
2391  }
2392  for(;;) {
2393  /* SIGHUP causes the root server process to reconfigure
2394  * itself and add new export servers for each newly
2395  * found export configuration group, i.e. spawn new
2396  * server processes for each previously non-existent
2397  * export. This does not alter old runtime configuration
2398  * but just appends new exports. */
2399  if (is_sighup_caught) {
2400  int n;
2401  GError *gerror = NULL;
2402 
2403  msg(LOG_INFO, "reconfiguration request received");
2404  is_sighup_caught = 0; /* Reset to allow catching
2405  * it again. */
2406 
2407  n = append_new_servers(servers, &gerror);
2408  if (n == -1)
2409  msg(LOG_ERR, "failed to append new servers: %s",
2410  gerror->message);
2411 
2412  for (i = servers->len - n; i < servers->len; ++i) {
2413  const SERVER server = g_array_index(servers,
2414  SERVER, i);
2415 
2416  if (server.socket >= 0) {
2417  FD_SET(server.socket, &mset);
2418  max = server.socket > max ? server.socket : max;
2419  }
2420 
2421  msg(LOG_INFO, "reconfigured new server: %s",
2422  server.servename);
2423  }
2424  }
2425 
2426  memcpy(&rset, &mset, sizeof(fd_set));
2427  if(select(max+1, &rset, NULL, NULL, NULL)>0) {
2428  int net;
2429 
2430  DEBUG("accept, ");
2431  for(i=0; i < modernsocks->len; i++) {
2432  int sock = g_array_index(modernsocks, int, i);
2433  if(!FD_ISSET(sock, &rset)) {
2434  continue;
2435  }
2436  CLIENT *client;
2437 
2438  if((net=accept(sock, (struct sockaddr *) &addrin, &addrinlen)) < 0) {
2439  err_nonfatal("accept: %m");
2440  continue;
2441  }
2442  client = negotiate(net, NULL, servers, NEG_INIT | NEG_MODERN);
2443  if(!client) {
2444  close(net);
2445  continue;
2446  }
2447  handle_connection(servers, net, client->server, client);
2448  }
2449  for(i=0; i < servers->len; i++) {
2450  SERVER *serve;
2451 
2452  serve=&(g_array_index(servers, SERVER, i));
2453  if(sock < 0) {
2454  continue;
2455  }
2456  if(FD_ISSET(serve->socket, &rset)) {
2457  if ((net=accept(serve->socket, (struct sockaddr *) &addrin, &addrinlen)) < 0) {
2458  err_nonfatal("accept: %m");
2459  continue;
2460  }
2461  handle_connection(servers, net, serve, NULL);
2462  }
2463  }
2464  }
2465  }
2466 }
2467 void serveloop(GArray* servers) G_GNUC_NORETURN;
2468 
2469 /**
2470  * Set server socket options.
2471  *
2472  * @param socket a socket descriptor of the server
2473  *
2474  * @param gerror a pointer to an error object pointer used for reporting
2475  * errors. On error, if gerror is not NULL, *gerror is set and -1
2476  * is returned.
2477  *
2478  * @return 0 on success, -1 on error
2479  **/
2480 int dosockopts(const int socket, GError **const gerror) {
2481 #ifndef sun
2482  int yes=1;
2483 #else
2484  char yes='1';
2485 #endif /* sun */
2486  struct linger l;
2487 
2488  /* lose the pesky "Address already in use" error message */
2489  if (setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
2490  g_set_error(gerror, NBDS_ERR, NBDS_ERR_SO_REUSEADDR,
2491  "failed to set socket option SO_REUSEADDR: %s",
2492  strerror(errno));
2493  return -1;
2494  }
2495  l.l_onoff = 1;
2496  l.l_linger = 10;
2497  if (setsockopt(socket,SOL_SOCKET,SO_LINGER,&l,sizeof(l)) == -1) {
2498  g_set_error(gerror, NBDS_ERR, NBDS_ERR_SO_LINGER,
2499  "failed to set socket option SO_LINGER: %s",
2500  strerror(errno));
2501  return -1;
2502  }
2503  if (setsockopt(socket,SOL_SOCKET,SO_KEEPALIVE,&yes,sizeof(int)) == -1) {
2504  g_set_error(gerror, NBDS_ERR, NBDS_ERR_SO_KEEPALIVE,
2505  "failed to set socket option SO_KEEPALIVE: %s",
2506  strerror(errno));
2507  return -1;
2508  }
2509 
2510  return 0;
2511 }
2512 
2513 /**
2514  * Connect a server's socket.
2515  *
2516  * @param serve the server we want to connect.
2517  **/
2518 int setup_serve(SERVER *const serve, GError **const gerror) {
2519  struct addrinfo hints;
2520  struct addrinfo *ai = NULL;
2521  gchar *port = NULL;
2522  int e;
2523  int retval = -1;
2524 
2525  /* Without this, it's possible that socket == 0, even if it's
2526  * not initialized at all. And that would be wrong because 0 is
2527  * totally legal value for properly initialized descriptor. This
2528  * line is required to ensure that unused/uninitialized
2529  * descriptors are marked as such (new style configuration
2530  * case). Currently, servers are being initialized in multiple
2531  * places, and some of the them do the socket initialization
2532  * incorrectly. This is the only point common to all code paths,
2533  * and therefore setting -1 is put here. However, the whole
2534  * server initialization procedure should be extracted to its
2535  * own function and all code paths wanting to mess with servers
2536  * should initialize servers with that function.
2537  *
2538  * TODO: fix server initialization */
2539  serve->socket = -1;
2540 
2541  if(!(glob_flags & F_OLDSTYLE)) {
2542  return serve->servename ? 1 : 0;
2543  }
2544  memset(&hints,'\0',sizeof(hints));
2545  hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG | AI_NUMERICSERV;
2546  hints.ai_socktype = SOCK_STREAM;
2547  hints.ai_family = serve->socket_family;
2548 
2549  port = g_strdup_printf("%d", serve->port);
2550  if (!port) {
2551  g_set_error(gerror, NBDS_ERR, NBDS_ERR_SYS,
2552  "failed to open an export socket: "
2553  "failed to convert a port number to a string: %s",
2554  strerror(errno));
2555  goto out;
2556  }
2557 
2558  e = getaddrinfo(serve->listenaddr,port,&hints,&ai);
2559 
2560  g_free(port);
2561 
2562  if(e != 0) {
2563  g_set_error(gerror, NBDS_ERR, NBDS_ERR_GAI,
2564  "failed to open an export socket: "
2565  "failed to get address info: %s",
2566  gai_strerror(e));
2567  goto out;
2568  }
2569 
2570  if(serve->socket_family == AF_UNSPEC)
2571  serve->socket_family = ai->ai_family;
2572 
2573 #ifdef WITH_SDP
2574  if ((serve->flags) && F_SDP) {
2575  if (ai->ai_family == AF_INET)
2576  ai->ai_family = AF_INET_SDP;
2577  else (ai->ai_family == AF_INET6)
2578  ai->ai_family = AF_INET6_SDP;
2579  }
2580 #endif
2581  if ((serve->socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) {
2582  g_set_error(gerror, NBDS_ERR, NBDS_ERR_SOCKET,
2583  "failed to open an export socket: "
2584  "failed to create a socket: %s",
2585  strerror(errno));
2586  goto out;
2587  }
2588 
2589  if (dosockopts(serve->socket, gerror) == -1) {
2590  g_prefix_error(gerror, "failed to open an export socket: ");
2591  goto out;
2592  }
2593 
2594  DEBUG("Waiting for connections... bind, ");
2595  e = bind(serve->socket, ai->ai_addr, ai->ai_addrlen);
2596  if (e != 0 && errno != EADDRINUSE) {
2597  g_set_error(gerror, NBDS_ERR, NBDS_ERR_BIND,
2598  "failed to open an export socket: "
2599  "failed to bind an address to a socket: %s",
2600  strerror(errno));
2601  goto out;
2602  }
2603  DEBUG("listen, ");
2604  if (listen(serve->socket, 1) < 0) {
2605  g_set_error(gerror, NBDS_ERR, NBDS_ERR_BIND,
2606  "failed to open an export socket: "
2607  "failed to start listening on a socket: %s",
2608  strerror(errno));
2609  goto out;
2610  }
2611 
2612  retval = serve->servename ? 1 : 0;
2613 out:
2614 
2615  if (retval == -1 && serve->socket >= 0) {
2616  close(serve->socket);
2617  serve->socket = -1;
2618  }
2619  freeaddrinfo (ai);
2620 
2621  return retval;
2622 }
2623 
2624 int open_modern(const gchar *const addr, const gchar *const port,
2625  GError **const gerror) {
2626  struct addrinfo hints;
2627  struct addrinfo* ai = NULL;
2628  struct addrinfo* ai_bak;
2629  struct sock_flags;
2630  int e;
2631  int retval = -1;
2632  int i=0;
2633  int sock = -1;
2634 
2635  memset(&hints, '\0', sizeof(hints));
2636  hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
2637  hints.ai_socktype = SOCK_STREAM;
2638  hints.ai_family = AF_UNSPEC;
2639  hints.ai_protocol = IPPROTO_TCP;
2640  e = getaddrinfo(addr, port ? port : NBD_DEFAULT_PORT, &hints, &ai);
2641  ai_bak = ai;
2642  if(e != 0) {
2643  g_set_error(gerror, NBDS_ERR, NBDS_ERR_GAI,
2644  "failed to open a modern socket: "
2645  "failed to get address info: %s",
2646  gai_strerror(e));
2647  goto out;
2648  }
2649 
2650  while(ai != NULL) {
2651  sock = -1;
2652 
2653  if((sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))<0) {
2654  g_set_error(gerror, NBDS_ERR, NBDS_ERR_SOCKET,
2655  "failed to open a modern socket: "
2656  "failed to create a socket: %s",
2657  strerror(errno));
2658  goto out;
2659  }
2660 
2661  if (dosockopts(sock, gerror) == -1) {
2662  g_prefix_error(gerror, "failed to open a modern socket: ");
2663  goto out;
2664  }
2665 
2666  if(bind(sock, ai->ai_addr, ai->ai_addrlen)) {
2667  /* This is so wrong.
2668  *
2669  * Linux will return multiple entries for the
2670  * same system when we ask it for something
2671  * AF_UNSPEC, even though the first entry will
2672  * listen to both protocols. Other systems will
2673  * return multiple entries too, but we actually
2674  * do need to open both. Sigh.
2675  *
2676  * Handle it by ignoring EADDRINUSE if we've
2677  * already got at least one socket open
2678  */
2679  if(errno == EADDRINUSE && modernsocks->len > 0) {
2680  goto next;
2681  }
2682  g_set_error(gerror, NBDS_ERR, NBDS_ERR_BIND,
2683  "failed to open a modern socket: "
2684  "failed to bind an address to a socket: %s",
2685  strerror(errno));
2686  goto out;
2687  }
2688 
2689  if(listen(sock, 10) <0) {
2690  g_set_error(gerror, NBDS_ERR, NBDS_ERR_BIND,
2691  "failed to open a modern socket: "
2692  "failed to start listening on a socket: %s",
2693  strerror(errno));
2694  goto out;
2695  }
2696  g_array_append_val(modernsocks, sock);
2697  next:
2698  ai = ai->ai_next;
2699  }
2700 
2701  retval = 0;
2702 out:
2703 
2704  if (retval == -1 && sock >= 0) {
2705  close(sock);
2706  }
2707  if(ai_bak)
2708  freeaddrinfo(ai_bak);
2709 
2710  return retval;
2711 }
2712 
2713 /**
2714  * Connect our servers.
2715  **/
2716 void setup_servers(GArray *const servers, const gchar *const modernaddr,
2717  const gchar *const modernport) {
2718  int i;
2719  struct sigaction sa;
2720  int want_modern=0;
2721 
2722  for(i=0;i<servers->len;i++) {
2723  GError *gerror = NULL;
2724  SERVER *server = &g_array_index(servers, SERVER, i);
2725  int ret;
2726 
2727  ret = setup_serve(server, &gerror);
2728  if (ret == -1) {
2729  msg(LOG_ERR, "failed to setup servers: %s",
2730  gerror->message);
2731  g_clear_error(&gerror);
2732  exit(EXIT_FAILURE);
2733  }
2734  want_modern |= ret;
2735  }
2736  if(want_modern) {
2737  GError *gerror = NULL;
2738  if (open_modern(modernaddr, modernport, &gerror) == -1) {
2739  msg(LOG_ERR, "failed to setup servers: %s",
2740  gerror->message);
2741  g_clear_error(&gerror);
2742  exit(EXIT_FAILURE);
2743  }
2744  }
2745  children=g_hash_table_new_full(g_int_hash, g_int_equal, NULL, destroy_pid_t);
2746 
2747  sa.sa_handler = sigchld_handler;
2748  sigemptyset(&sa.sa_mask);
2749  sigaddset(&sa.sa_mask, SIGTERM);
2750  sa.sa_flags = SA_RESTART;
2751  if(sigaction(SIGCHLD, &sa, NULL) == -1)
2752  err("sigaction: %m");
2753 
2754  sa.sa_handler = sigterm_handler;
2755  sigemptyset(&sa.sa_mask);
2756  sigaddset(&sa.sa_mask, SIGCHLD);
2757  sa.sa_flags = SA_RESTART;
2758  if(sigaction(SIGTERM, &sa, NULL) == -1)
2759  err("sigaction: %m");
2760 
2761  sa.sa_handler = sighup_handler;
2762  sigemptyset(&sa.sa_mask);
2763  sa.sa_flags = SA_RESTART;
2764  if(sigaction(SIGHUP, &sa, NULL) == -1)
2765  err("sigaction: %m");
2766 }
2767 
2768 /**
2769  * Go daemon (unless we specified at compile time that we didn't want this)
2770  * @param serve the first server of our configuration. If its port is zero,
2771  * then do not daemonize, because we're doing inetd then. This parameter
2772  * is only used to create a PID file of the form
2773  * /var/run/nbd-server.&lt;port&gt;.pid; it's not modified in any way.
2774  **/
2775 #if !defined(NODAEMON)
2776 void daemonize(SERVER* serve) {
2777  FILE*pidf;
2779  if(serve && !(serve->port)) {
2780  return;
2781  }
2782  if(daemon(0,0)<0) {
2783  err("daemon");
2784  }
2785  if(!*pidftemplate) {
2786  if(serve) {
2787  strncpy(pidftemplate, "/var/run/nbd-server.%d.pid", 255);
2788  } else {
2789  strncpy(pidftemplate, "/var/run/nbd-server.pid", 255);
2790  }
2791  }
2792  snprintf(pidfname, 255, pidftemplate, serve ? serve->port : 0);
2793  pidf=fopen(pidfname, "w");
2794  if(pidf) {
2795  fprintf(pidf,"%d\n", (int)getpid());
2796  fclose(pidf);
2797  } else {
2798  perror("fopen");
2799  fprintf(stderr, "Not fatal; continuing");
2800  }
2801 }
2802 #else
2803 #define daemonize(serve)
2804 #endif /* !defined(NODAEMON) */
2805 
2806 /*
2807  * Everything beyond this point (in the file) is run in non-daemon mode.
2808  * The stuff above daemonize() isn't.
2809  */
2810 
2811 /**
2812  * Set up user-ID and/or group-ID
2813  **/
2814 void dousers(const gchar *const username, const gchar *const groupname) {
2815  struct passwd *pw;
2816  struct group *gr;
2817  gchar* str;
2818  if (groupname) {
2819  gr = getgrnam(groupname);
2820  if(!gr) {
2821  str = g_strdup_printf("Invalid group name: %s", groupname);
2822  err(str);
2823  }
2824  if(setgid(gr->gr_gid)<0) {
2825  err("Could not set GID: %m");
2826  }
2827  }
2828  if (username) {
2829  pw = getpwnam(username);
2830  if(!pw) {
2831  str = g_strdup_printf("Invalid user name: %s", username);
2832  err(str);
2833  }
2834  if(setuid(pw->pw_uid)<0) {
2835  err("Could not set UID: %m");
2836  }
2837  }
2838 }
2839 
2840 #ifndef ISSERVER
2841 void glib_message_syslog_redirect(const gchar *log_domain,
2842  GLogLevelFlags log_level,
2843  const gchar *message,
2844  gpointer user_data)
2845 {
2846  int level=LOG_DEBUG;
2847 
2848  switch( log_level )
2849  {
2850  case G_LOG_FLAG_FATAL:
2851  case G_LOG_LEVEL_CRITICAL:
2852  case G_LOG_LEVEL_ERROR:
2853  level=LOG_ERR;
2854  break;
2855  case G_LOG_LEVEL_WARNING:
2856  level=LOG_WARNING;
2857  break;
2858  case G_LOG_LEVEL_MESSAGE:
2859  case G_LOG_LEVEL_INFO:
2860  level=LOG_INFO;
2861  break;
2862  case G_LOG_LEVEL_DEBUG:
2863  level=LOG_DEBUG;
2864  break;
2865  default:
2866  level=LOG_ERR;
2867  }
2868  syslog(level, "%s", message);
2869 }
2870 #endif
2871 
2872 /**
2873  * Main entry point...
2874  **/
2875 int main(int argc, char *argv[]) {
2876  SERVER *serve;
2877  GArray *servers;
2878  GError *err=NULL;
2879  struct generic_conf genconf;
2880 
2881  memset(&genconf, 0, sizeof(struct generic_conf));
2882 
2883  if (sizeof( struct nbd_request )!=28) {
2884  fprintf(stderr,"Bad size of structure. Alignment problems?\n");
2885  exit(EXIT_FAILURE) ;
2886  }
2887 
2888  memset(pidftemplate, '\0', 256);
2889 
2890  modernsocks = g_array_new(FALSE, FALSE, sizeof(int));
2891 
2892  logging();
2893  config_file_pos = g_strdup(CFILE);
2894  serve=cmdline(argc, argv);
2895 
2896  servers = parse_cfile(config_file_pos, &genconf, &err);
2897 
2898  /* Update global variables with parsed values. This will be
2899  * removed once we get rid of global configuration variables. */
2900  glob_flags |= genconf.flags;
2901 
2902  if(serve) {
2903  serve->socket_family = AF_UNSPEC;
2904 
2905  append_serve(serve, servers);
2906 
2907  if (!(serve->port)) {
2908  CLIENT *client;
2909 #ifndef ISSERVER
2910  /* You really should define ISSERVER if you're going to use
2911  * inetd mode, but if you don't, closing stdout and stderr
2912  * (which inetd had connected to the client socket) will let it
2913  * work. */
2914  close(1);
2915  close(2);
2916  open("/dev/null", O_WRONLY);
2917  open("/dev/null", O_WRONLY);
2918  g_log_set_default_handler( glib_message_syslog_redirect, NULL );
2919 #endif
2920  client=g_malloc(sizeof(CLIENT));
2921  client->server=serve;
2922  client->net=-1;
2923  client->exportsize=OFFT_MAX;
2924  if (set_peername(0, client))
2925  exit(EXIT_FAILURE);
2926  serveconnection(client);
2927  return 0;
2928  }
2929  }
2930 
2931  if(!servers || !servers->len) {
2932  if(err && !(err->domain == NBDS_ERR
2933  && err->code == NBDS_ERR_CFILE_NOTFOUND)) {
2934  g_warning("Could not parse config file: %s",
2935  err ? err->message : "Unknown error");
2936  }
2937  }
2938  if(serve) {
2939  g_warning("Specifying an export on the command line is deprecated.");
2940  g_warning("Please use a configuration file instead.");
2941  }
2942 
2943  if((!serve) && (!servers||!servers->len)) {
2944  if(err)
2945  g_message("No configured exports; quitting.");
2946  exit(EXIT_FAILURE);
2947  }
2948  if (!dontfork)
2949  daemonize(serve);
2950  setup_servers(servers, genconf.modernaddr, genconf.modernport);
2951  dousers(genconf.user, genconf.group);
2952 
2953  serveloop(servers);
2954 }
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&#39;s socket.
Definition: nbd-server.c:2520
static void consume(int f, void *buf, size_t len, size_t bufsiz)
Consume data from an FD that we don&#39;t want.
Definition: nbd-server.c:408
This parameter is a string.
Definition: nbd-server.c:269
gchar * servename
name of the export as selected by nbd-client
Definition: nbd-server.c:230
void glib_message_syslog_redirect(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
Definition: nbd-server.c:2843
#define NBD_OPT_LIST
Definition: cliserv.h:154
void sigterm_handler(int s)
Handle SIGTERM and dispatch it to our children.
Definition: nbd-server.c:1122
__be32 type
Definition: nbd.h:67
GArray * export
array of FILE_INFO of exported files; array size is always 1 unless we&#39;re doing the multiple file opt...
Definition: nbd-server.c:247
int append_serve(const SERVER *const s, GArray *const a)
append new server to array
Definition: nbd-server.c:709
Variables associated with a server.
Definition: nbd-server.c:213
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:647
Replacing all dots in an ip address by a / before doing the same as in IPLIT.
Definition: nbd-server.c:205
void setup_servers(GArray *const servers, const gchar *const modernaddr, const gchar *const modernport)
Connect our servers.
Definition: nbd-server.c:2718
#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:652
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:638
SERVER * server
The server this client is getting data from.
Definition: nbd-server.c:251
#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:228
int clientfeats
Features supported by this client.
Definition: nbd-server.c:260
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:650
#define NEG_MODERN
Definition: nbd-server.c:180
void dump_section(SERVER *serve, gchar *section_header)
Definition: nbd-server.c:459
u32 difffilelen
number of pages in difffile
Definition: nbd-server.c:256
#define CFILE
Definition: nbd-server.c:114
This parameter is a boolean.
Definition: nbd-server.c:270
#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:637
void serveloop(GArray *servers)
Loop through the available servers, and serve them.
Definition: nbd-server.c:2365
int fhandle
file descriptor
Definition: nbd-server.c:239
int dosockopts(const int socket, GError **const gerror)
Set server socket options.
Definition: nbd-server.c:2482
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:2305
gchar * modernport
port of the modern socket
Definition: nbd-server.c:297
gchar * user
user we run the server as
Definition: nbd-server.c:294
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:240
Failed to start listening on a socket.
Definition: nbd-server.c:651
#define fdatasync(arg)
Definition: cliserv.h:44
Failed to create a socket.
Definition: nbd-server.c:649
A (required) key is missing.
Definition: nbd-server.c:636
int authorized_client(CLIENT *opts)
Check whether a client is allowed to connect.
Definition: nbd-server.c:331
#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 int append_new_servers(GArray *const servers, GError **const gerror)
Parse configuration files and add servers to the array if they don&#39;t already exist there...
Definition: nbd-server.c:2331
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:204
int flags
flags associated with this exported file
Definition: nbd-server.c:220
This parameter is an integer.
Definition: nbd-server.c:267
#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
GArray * modernsocks
Sockets for the modern handler.
Definition: nbd-server.c:187
A directory requested does not exist.
Definition: nbd-server.c:643
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:1111
gchar * exportname
(unprocessed) filename of the file we&#39;re exporting
Definition: nbd-server.c:214
int net
The actual client socket.
Definition: nbd-server.c:250
#define NBD_FLAG_SEND_FLUSH
Definition: nbd.h:46
#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
void usage(char *errmsg,...)
Definition: nbd-client.c:381
Every subnet in its own directory.
Definition: nbd-server.c:207
#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:2626
unsigned int port
port we&#39;re exporting this file at
Definition: nbd-server.c:218
gboolean required
Whether this is a required (as opposed to optional) parameter.
Definition: nbd-server.c:279
#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:232
A config file was specified that does not define any exports.
Definition: nbd-server.c:639
gchar * listenaddr
The IP address we&#39;re listening on.
Definition: nbd-server.c:217
#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:245
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:215
#define AI_NUMERICSERV
Definition: netdb-compat.h:21
The reserved port was specified for an old-style export.
Definition: nbd-server.c:641
static const char * getcommandname(uint64_t command)
Translate a command name into human readable form.
Definition: nbd-server.c:307
int socket
The socket of this server.
Definition: nbd-server.c:221
Error occurred during readdir()
Definition: nbd-server.c:644
gchar * modernaddr
address of the modern socket
Definition: nbd-server.c:296
bool logged_oversized
whether we logged oversized requests already
Definition: nbd-server.c:197
int difffile
filedescriptor of copyonwrite file.
Definition: nbd-server.c:253
SERVER * cmdline(int argc, char *argv[])
Parse the command line.
Definition: nbd-server.c:488
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:298
#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:385
char pidfname[256]
name of our PID file
Definition: nbd-server.c:174
Variables associated with a client socket.
Definition: nbd-server.c:238
int dontfork
Definition: nbd-server.c:123
Failed to set SO_REUSEADDR to a socket.
Definition: nbd-server.c:646
The configuration file is not found.
Definition: nbd-server.c:634
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:257
NBDS_ERRS
NBD server error codes.
Definition: nbd-server.c:633
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&#39;t want this)
Definition: nbd-server.c:2778
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:266
The (required) group &quot;generic&quot; is missing.
Definition: nbd-server.c:635
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:628
void sigchld_handler(int s)
Signal handler for SIGCHLD.
Definition: nbd-server.c:1084
GArray * do_cfile_dir(gchar *dir, GError **e)
Parse config file snippets in a directory.
Definition: nbd-server.c:774
int transactionlogfd
fd for transaction log
Definition: nbd-server.c:259
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&#39;re exporting
Definition: nbd-server.c:244
int max_connections
maximum number of opened connections
Definition: nbd-server.c:231
VIRT_STYLE virtstyle
The style of virtualization, if any.
Definition: nbd-server.c:223
#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:648
static volatile sig_atomic_t is_sighup_caught
Flag set by SIGHUP handler to mark a reconfiguration request.
Definition: nbd-server.c:182
__be32 len
Definition: nbd.h:70
VIRT_STYLE
Types of virtuatlization.
Definition: nbd-server.c:202
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:660
__be64 from
Definition: nbd.h:69
int socket_family
family of the socket
Definition: nbd-server.c:222
gchar * prerun
command to be ran after connecting a client, but before starting to serve
Definition: nbd-server.c:226
static void handle_connection(GArray *servers, int net, SERVER *serve, CLIENT *client)
Definition: nbd-server.c:2204
#define NBD_FLAG_SEND_TRIM
Definition: nbd.h:49
int main(int argc, char **argv)
This parameter is an integer.
Definition: nbd-server.c:268
#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:295
#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:219
static void writeit(int f, void *buf, size_t len)
Write data from a buffer into a filedescriptor.
Definition: nbd-server.c:425
#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:258
#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:252
void dousers(const gchar *const username, const gchar *const groupname)
Set up user-ID and/or group-ID.
Definition: nbd-server.c:2816
Failed to set SO_LINGER to a socket.
Definition: nbd-server.c:645
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:203
uint8_t cidrlen
The length of the mask when we use CIDR-style virtualization.
Definition: nbd-server.c:224
#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&#39;re exporting
Definition: nbd-server.c:246
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
void negotiate(int sock, u64 *rsize64, u32 *flags, char *name, uint32_t needed_flags, uint32_t client_flags, uint32_t do_opts)
Definition: nbd-client.c:223
Configuration file values of the &quot;generic&quot; section.
Definition: nbd-server.c:293
Configuration file values.
Definition: nbd-server.c:276
#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:850
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