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