2 * Network Block Device - server
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>
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
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
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
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>
58 /* Includes LFS defines, which defines behaviours of some of the following
59 * headers, so must come before those */
62 #include <sys/types.h>
63 #include <sys/socket.h>
65 #include <sys/select.h> /* select */
66 #include <sys/wait.h> /* wait */
67 #ifdef HAVE_SYS_IOCTL_H
68 #include <sys/ioctl.h>
70 #include <sys/param.h>
71 #ifdef HAVE_SYS_MOUNT_H
72 #include <sys/mount.h> /* For BLKGETSIZE */
74 #include <signal.h> /* sigaction */
76 #include <netinet/tcp.h>
77 #include <netinet/in.h>
85 #include <arpa/inet.h>
95 /* used in cliserv.h, so must come first */
96 #define MY_NAME "nbd_server"
100 #include <sdp_inet.h>
103 /** Default position of the config file */
105 #define SYSCONFDIR "/etc"
107 #define CFILE SYSCONFDIR "/nbd-server/config"
109 /** Where our config file actually is */
110 gchar* config_file_pos;
112 /** What user we're running as */
114 /** What group we're running as */
115 gchar* rungroup=NULL;
116 /** whether to export using the old negotiation protocol (port-based) */
117 gboolean do_oldstyle=FALSE;
119 /** Logging macros, now nothing goes to syslog unless you say ISSERVER */
121 #define msg2(a,b) syslog(a,b)
122 #define msg3(a,b,c) syslog(a,b,c)
123 #define msg4(a,b,c,d) syslog(a,b,c,d)
125 #define msg2(a,b) g_message(b)
126 #define msg3(a,b,c) g_message(b,c)
127 #define msg4(a,b,c,d) g_message(b,c,d)
130 /* Debugging macros */
133 #define DEBUG( a ) printf( a )
134 #define DEBUG2( a,b ) printf( a,b )
135 #define DEBUG3( a,b,c ) printf( a,b,c )
136 #define DEBUG4( a,b,c,d ) printf( a,b,c,d )
139 #define DEBUG2( a,b )
140 #define DEBUG3( a,b,c )
141 #define DEBUG4( a,b,c,d )
143 #ifndef PACKAGE_VERSION
144 #define PACKAGE_VERSION ""
147 * The highest value a variable of type off_t can reach. This is a signed
148 * integer, so set all bits except for the leftmost one.
150 #define OFFT_MAX ~((off_t)1<<(sizeof(off_t)*8-1))
151 #define LINELEN 256 /**< Size of static buffer used to read the
152 authorization file (yuck) */
153 #define BUFSIZE ((1024*1024)+sizeof(struct nbd_reply)) /**< Size of buffer that can hold requests */
154 #define DIFFPAGESIZE 4096 /**< diff file uses those chunks */
155 #define F_READONLY 1 /**< flag to tell us a file is readonly */
156 #define F_MULTIFILE 2 /**< flag to tell us a file is exported using -m */
157 #define F_COPYONWRITE 4 /**< flag to tell us a file is exported using
159 #define F_AUTOREADONLY 8 /**< flag to tell us a file is set to autoreadonly */
160 #define F_SPARSE 16 /**< flag to tell us copyronwrite should use a sparse file */
161 #define F_SDP 32 /**< flag to tell us the export should be done using the Socket Direct Protocol for RDMA */
162 #define F_SYNC 64 /**< Whether to fsync() after a write */
163 GHashTable *children;
164 char pidfname[256]; /**< name of our PID file */
165 char pidftemplate[256]; /**< template to be used for the filename of the PID file */
166 char default_authname[] = SYSCONFDIR "/nbd-server/allow"; /**< default name of allow file */
168 int modernsock=0; /**< Socket for the modern handler. Not used
169 if a client was only specified on the
170 command line; only port used if
171 oldstyle is set to false (and then the
172 command-line client isn't used, gna gna) */
173 char* modern_listen; /**< listenaddr value for modernsock */
176 * Types of virtuatlization
179 VIRT_NONE=0, /**< No virtualization */
180 VIRT_IPLIT, /**< Literal IP address as part of the filename */
181 VIRT_IPHASH, /**< Replacing all dots in an ip address by a / before
182 doing the same as in IPLIT */
183 VIRT_CIDR, /**< Every subnet in its own directory */
187 * Variables associated with a server.
190 gchar* exportname; /**< (unprocessed) filename of the file we're exporting */
191 off_t expected_size; /**< size of the exported file as it was told to
192 us through configuration */
193 gchar* listenaddr; /**< The IP address we're listening on */
194 unsigned int port; /**< port we're exporting this file at */
195 char* authname; /**< filename of the authorization file */
196 int flags; /**< flags associated with this exported file */
197 int socket; /**< The socket of this server. */
198 int socket_family; /**< family of the socket */
199 VIRT_STYLE virtstyle;/**< The style of virtualization, if any */
200 uint8_t cidrlen; /**< The length of the mask when we use
201 CIDR-style virtualization */
202 gchar* prerun; /**< command to be ran after connecting a client,
203 but before starting to serve */
204 gchar* postrun; /**< command that will be ran after the client
206 gchar* servename; /**< name of the export as selected by nbd-client */
207 int max_connections; /**< maximum number of opened connections */
211 * Variables associated with a client socket.
214 int fhandle; /**< file descriptor */
215 off_t startoff; /**< starting offset of this file */
219 off_t exportsize; /**< size of the file we're exporting */
220 char *clientname; /**< peer */
221 char *exportname; /**< (processed) filename of the file we're exporting */
222 GArray *export; /**< array of FILE_INFO of exported files;
223 array size is always 1 unless we're
224 doing the multiple file option */
225 int net; /**< The actual client socket */
226 SERVER *server; /**< The server this client is getting data from */
227 char* difffilename; /**< filename of the copy-on-write file, if any */
228 int difffile; /**< filedescriptor of copyonwrite file. @todo
229 shouldn't this be an array too? (cfr export) Or
230 make -m and -c mutually exclusive */
231 u32 difffilelen; /**< number of pages in difffile */
232 u32 *difmap; /**< see comment on the global difmap for this one */
233 gboolean modern; /**< client was negotiated using modern negotiation protocol */
237 * Type of configuration file values
240 PARAM_INT, /**< This parameter is an integer */
241 PARAM_STRING, /**< This parameter is a string */
242 PARAM_BOOL, /**< This parameter is a boolean */
246 * Configuration file values
249 gchar *paramname; /**< Name of the parameter, as it appears in
251 gboolean required; /**< Whether this is a required (as opposed to
252 optional) parameter */
253 PARAM_TYPE ptype; /**< Type of the parameter. */
254 gpointer target; /**< Pointer to where the data of this
255 parameter should be written. If ptype is
256 PARAM_BOOL, the data is or'ed rather than
258 gint flagval; /**< Flag mask for this parameter in case ptype
263 * Check whether a client is allowed to connect. Works with an authorization
264 * file which contains one line per machine, no wildcards.
266 * @param opts The client who's trying to connect.
267 * @return 0 - authorization refused, 1 - OK
269 int authorized_client(CLIENT *opts) {
270 const char *ERRMSG="Invalid entry '%s' in authfile '%s', so, refusing all connections.";
275 struct in_addr client;
276 struct in_addr cltemp;
279 if ((f=fopen(opts->server->authname,"r"))==NULL) {
280 msg4(LOG_INFO,"Can't open authorization file %s (%s).",
281 opts->server->authname,strerror(errno)) ;
285 inet_aton(opts->clientname, &client);
286 while (fgets(line,LINELEN,f)!=NULL) {
287 if((tmp=index(line, '/'))) {
288 if(strlen(line)<=tmp-line) {
289 msg4(LOG_CRIT, ERRMSG, line, opts->server->authname);
293 if(!inet_aton(line,&addr)) {
294 msg4(LOG_CRIT, ERRMSG, line, opts->server->authname);
297 len=strtol(tmp, NULL, 0);
298 addr.s_addr>>=32-len;
299 addr.s_addr<<=32-len;
300 memcpy(&cltemp,&client,sizeof(client));
301 cltemp.s_addr>>=32-len;
302 cltemp.s_addr<<=32-len;
303 if(addr.s_addr == cltemp.s_addr) {
307 if (strncmp(line,opts->clientname,strlen(opts->clientname))==0) {
317 * Read data from a file descriptor into a buffer
319 * @param f a file descriptor
320 * @param buf a buffer
321 * @param len the number of bytes to be read
323 static inline void readit(int f, void *buf, size_t len) {
327 if ((res = read(f, buf, len)) <= 0) {
328 if(errno != EAGAIN) {
329 err("Read failed: %m");
339 * Write data from a buffer into a filedescriptor
341 * @param f a file descriptor
342 * @param buf a buffer containing data
343 * @param len the number of bytes to be written
345 static inline void writeit(int f, void *buf, size_t len) {
349 if ((res = write(f, buf, len)) <= 0)
350 err("Send failed: %m");
357 * Print out a message about how to use nbd-server. Split out to a separate
358 * function so that we can call it from multiple places
361 printf("This is nbd-server version " VERSION "\n");
362 printf("Usage: [ip:|ip6@]port file_to_export [size][kKmM] [-l authorize_file] [-r] [-m] [-c] [-C configuration file] [-p PID file name] [-o section name] [-M max connections]\n"
363 "\t-r|--read-only\t\tread only\n"
364 "\t-m|--multi-file\t\tmultiple file\n"
365 "\t-c|--copy-on-write\tcopy on write\n"
366 "\t-C|--config-file\tspecify an alternate configuration file\n"
367 "\t-l|--authorize-file\tfile with list of hosts that are allowed to\n\t\t\t\tconnect.\n"
368 "\t-p|--pid-file\t\tspecify a filename to write our PID to\n"
369 "\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"
370 "\t-M|--max-connections\tspecify the maximum number of opened connections\n\n"
371 "\tif port is set to 0, stdin is used (for running from inetd)\n"
372 "\tif file_to_export contains '%%s', it is substituted with the IP\n"
373 "\t\taddress of the machine trying to connect\n"
374 "\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");
375 printf("Using configuration file %s\n", CFILE);
378 /* Dumps a config file section of the given SERVER*, and exits. */
379 void dump_section(SERVER* serve, gchar* section_header) {
380 printf("[%s]\n", section_header);
381 printf("\texportname = %s\n", serve->exportname);
382 printf("\tlistenaddr = %s\n", serve->listenaddr);
383 printf("\tport = %d\n", serve->port);
384 if(serve->flags & F_READONLY) {
385 printf("\treadonly = true\n");
387 if(serve->flags & F_MULTIFILE) {
388 printf("\tmultifile = true\n");
390 if(serve->flags & F_COPYONWRITE) {
391 printf("\tcopyonwrite = true\n");
393 if(serve->expected_size) {
394 printf("\tfilesize = %lld\n", (long long int)serve->expected_size);
396 if(serve->authname) {
397 printf("\tauthfile = %s\n", serve->authname);
403 * Parse the command line.
405 * @param argc the argc argument to main()
406 * @param argv the argv argument to main()
408 SERVER* cmdline(int argc, char *argv[]) {
412 struct option long_options[] = {
413 {"read-only", no_argument, NULL, 'r'},
414 {"multi-file", no_argument, NULL, 'm'},
415 {"copy-on-write", no_argument, NULL, 'c'},
416 {"authorize-file", required_argument, NULL, 'l'},
417 {"config-file", required_argument, NULL, 'C'},
418 {"pid-file", required_argument, NULL, 'p'},
419 {"output-config", required_argument, NULL, 'o'},
420 {"max-connection", required_argument, NULL, 'M'},
427 gboolean do_output=FALSE;
428 gchar* section_header="";
434 serve=g_new0(SERVER, 1);
435 serve->authname = g_strdup(default_authname);
436 serve->virtstyle=VIRT_IPLIT;
437 while((c=getopt_long(argc, argv, "-C:cl:mo:rp:M:", long_options, &i))>=0) {
440 /* non-option argument */
441 switch(nonspecial++) {
443 if(strchr(optarg, ':') == strrchr(optarg, ':')) {
444 addr_port=g_strsplit(optarg, ":", 2);
446 /* Check for "@" - maybe user using this separator
449 g_strfreev(addr_port);
450 addr_port=g_strsplit(optarg, "@", 2);
453 addr_port=g_strsplit(optarg, "@", 2);
457 serve->port=strtol(addr_port[1], NULL, 0);
458 serve->listenaddr=g_strdup(addr_port[0]);
460 serve->listenaddr=NULL;
461 serve->port=strtol(addr_port[0], NULL, 0);
463 g_strfreev(addr_port);
466 serve->exportname = g_strdup(optarg);
467 if(serve->exportname[0] != '/') {
468 fprintf(stderr, "E: The to be exported file needs to be an absolute filename!\n");
473 last=strlen(optarg)-1;
475 if (suffix == 'k' || suffix == 'K' ||
476 suffix == 'm' || suffix == 'M')
478 es = (off_t)atoll(optarg);
486 serve->expected_size = es;
491 serve->flags |= F_READONLY;
494 serve->flags |= F_MULTIFILE;
498 section_header = g_strdup(optarg);
501 strncpy(pidftemplate, optarg, 256);
504 serve->flags |=F_COPYONWRITE;
507 g_free(config_file_pos);
508 config_file_pos=g_strdup(optarg);
511 g_free(serve->authname);
512 serve->authname=g_strdup(optarg);
515 serve->max_connections = strtol(optarg, NULL, 0);
523 /* What's left: the port to export, the name of the to be exported
524 * file, and, optionally, the size of the file, in that order. */
533 g_critical("Need a complete configuration on the command line to output a config file section!");
536 dump_section(serve, section_header);
542 * Error codes for config file parsing
545 CFILE_NOTFOUND, /**< The configuration file is not found */
546 CFILE_MISSING_GENERIC, /**< The (required) group "generic" is missing */
547 CFILE_KEY_MISSING, /**< A (required) key is missing */
548 CFILE_VALUE_INVALID, /**< A value is syntactically invalid */
549 CFILE_VALUE_UNSUPPORTED,/**< A value is not supported in this build */
550 CFILE_PROGERR, /**< Programmer error */
551 CFILE_NO_EXPORTS, /**< A config file was specified that does not
552 define any exports */
553 CFILE_INCORRECT_PORT, /**< The reserved port was specified for an
558 * Remove a SERVER from memory. Used from the hash table
560 void remove_server(gpointer s) {
564 g_free(server->exportname);
566 g_free(server->authname);
567 if(server->listenaddr)
568 g_free(server->listenaddr);
570 g_free(server->prerun);
572 g_free(server->postrun);
578 * @param s the old server we want to duplicate
579 * @return new duplicated server
581 SERVER* dup_serve(SERVER *s) {
582 SERVER *serve = NULL;
584 serve=g_new0(SERVER, 1);
589 serve->exportname = g_strdup(s->exportname);
591 serve->expected_size = s->expected_size;
594 serve->listenaddr = g_strdup(s->listenaddr);
596 serve->port = s->port;
599 serve->authname = strdup(s->authname);
601 serve->flags = s->flags;
602 serve->socket = s->socket;
603 serve->socket_family = s->socket_family;
604 serve->virtstyle = s->virtstyle;
605 serve->cidrlen = s->cidrlen;
608 serve->prerun = g_strdup(s->prerun);
611 serve->postrun = g_strdup(s->postrun);
614 serve->servename = g_strdup(s->servename);
616 serve->max_connections = s->max_connections;
622 * append new server to array
624 * @param a server array
625 * @return 0 success, -1 error
627 int append_serve(SERVER *s, GArray *a) {
629 struct addrinfo hints;
630 struct addrinfo *ai = NULL;
631 struct addrinfo *rp = NULL;
632 char host[NI_MAXHOST];
638 err("Invalid parsing server");
642 port = g_strdup_printf("%d", s->port);
644 memset(&hints,'\0',sizeof(hints));
645 hints.ai_family = AF_UNSPEC;
646 hints.ai_socktype = SOCK_STREAM;
647 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
648 hints.ai_protocol = IPPROTO_TCP;
650 e = getaddrinfo(s->listenaddr, port, &hints, &ai);
656 for (rp = ai; rp != NULL; rp = rp->ai_next) {
657 e = getnameinfo(rp->ai_addr, rp->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
659 if (e != 0) { // error
660 fprintf(stderr, "getnameinfo: %s\n", gai_strerror(e));
664 // duplicate server and set listenaddr to resolved IP address
667 ns->listenaddr = g_strdup(host);
668 ns->socket_family = rp->ai_family;
669 g_array_append_val(a, *ns);
677 fprintf(stderr, "getaddrinfo failed on listen host/address: %s (%s)\n", s->listenaddr ? s->listenaddr : "any", gai_strerror(e));
688 * Parse the config file.
690 * @param f the name of the config file
691 * @param e a GError. @see CFILE_ERRORS for what error values this function can
693 * @return a Array of SERVER* pointers, If the config file is empty or does not
694 * exist, returns an empty GHashTable; if the config file contains an
695 * error, returns NULL, and e is set appropriately
697 GArray* parse_cfile(gchar* f, GError** e) {
698 const char* DEFAULT_ERROR = "Could not parse %s in group %s: %s";
699 const char* MISSING_REQUIRED_ERROR = "Could not find required value %s in group %s: %s";
701 gchar *virtstyle=NULL;
703 { "exportname", TRUE, PARAM_STRING, NULL, 0 },
704 { "port", TRUE, PARAM_INT, NULL, 0 },
705 { "authfile", FALSE, PARAM_STRING, NULL, 0 },
706 { "filesize", FALSE, PARAM_INT, NULL, 0 },
707 { "virtstyle", FALSE, PARAM_STRING, NULL, 0 },
708 { "prerun", FALSE, PARAM_STRING, NULL, 0 },
709 { "postrun", FALSE, PARAM_STRING, NULL, 0 },
710 { "readonly", FALSE, PARAM_BOOL, NULL, F_READONLY },
711 { "multifile", FALSE, PARAM_BOOL, NULL, F_MULTIFILE },
712 { "copyonwrite", FALSE, PARAM_BOOL, NULL, F_COPYONWRITE },
713 { "sparse_cow", FALSE, PARAM_BOOL, NULL, F_SPARSE },
714 { "sdp", FALSE, PARAM_BOOL, NULL, F_SDP },
715 { "sync", FALSE, PARAM_BOOL, NULL, F_SYNC },
716 { "listenaddr", FALSE, PARAM_STRING, NULL, 0 },
717 { "maxconnections", FALSE, PARAM_INT, NULL, 0 },
719 const int lp_size=sizeof(lp)/sizeof(PARAM);
721 { "user", FALSE, PARAM_STRING, &runuser, 0 },
722 { "group", FALSE, PARAM_STRING, &rungroup, 0 },
723 { "oldstyle", FALSE, PARAM_BOOL, &do_oldstyle, 1 },
724 { "listenaddr", FALSE, PARAM_STRING, &modern_listen, 0 },
727 int p_size=sizeof(gp)/sizeof(PARAM);
730 const char *err_msg=NULL;
739 errdomain = g_quark_from_string("parse_cfile");
740 cfile = g_key_file_new();
741 retval = g_array_new(FALSE, TRUE, sizeof(SERVER));
742 if(!g_key_file_load_from_file(cfile, f, G_KEY_FILE_KEEP_COMMENTS |
743 G_KEY_FILE_KEEP_TRANSLATIONS, &err)) {
744 g_set_error(e, errdomain, CFILE_NOTFOUND, "Could not open config file %s.", f);
745 g_key_file_free(cfile);
748 startgroup = g_key_file_get_start_group(cfile);
749 if(!startgroup || strcmp(startgroup, "generic")) {
750 g_set_error(e, errdomain, CFILE_MISSING_GENERIC, "Config file does not contain the [generic] group!");
751 g_key_file_free(cfile);
754 groups = g_key_file_get_groups(cfile, NULL);
755 for(i=0;groups[i];i++) {
756 memset(&s, '\0', sizeof(SERVER));
757 lp[0].target=&(s.exportname);
758 lp[1].target=&(s.port);
759 lp[2].target=&(s.authname);
760 lp[3].target=&(s.expected_size);
761 lp[4].target=&(virtstyle);
762 lp[5].target=&(s.prerun);
763 lp[6].target=&(s.postrun);
764 lp[7].target=lp[8].target=lp[9].target=
765 lp[10].target=lp[11].target=
766 lp[12].target=&(s.flags);
767 lp[13].target=&(s.listenaddr);
768 lp[14].target=&(s.max_connections);
770 /* After the [generic] group, start parsing exports */
775 for(j=0;j<p_size;j++) {
776 g_assert(p[j].target != NULL);
777 g_assert(p[j].ptype==PARAM_INT||p[j].ptype==PARAM_STRING||p[j].ptype==PARAM_BOOL);
780 *((gint*)p[j].target) =
781 g_key_file_get_integer(cfile,
787 *((gchar**)p[j].target) =
788 g_key_file_get_string(cfile,
794 value = g_key_file_get_boolean(cfile,
796 p[j].paramname, &err);
799 *((gint*)p[j].target) |= p[j].flagval;
801 *((gint*)p[j].target) &= ~(p[j].flagval);
806 if(!strcmp(p[j].paramname, "port") && !strcmp(p[j].target, NBD_DEFAULT_PORT)) {
807 g_set_error(e, errdomain, CFILE_INCORRECT_PORT, "Config file specifies default port for oldstyle export");
808 g_key_file_free(cfile);
812 if(err->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
814 /* Ignore not-found error for optional values */
818 err_msg = MISSING_REQUIRED_ERROR;
821 err_msg = DEFAULT_ERROR;
823 g_set_error(e, errdomain, CFILE_VALUE_INVALID, err_msg, p[j].paramname, groups[i], err->message);
824 g_array_free(retval, TRUE);
826 g_key_file_free(cfile);
831 if(!strncmp(virtstyle, "none", 4)) {
832 s.virtstyle=VIRT_NONE;
833 } else if(!strncmp(virtstyle, "ipliteral", 9)) {
834 s.virtstyle=VIRT_IPLIT;
835 } else if(!strncmp(virtstyle, "iphash", 6)) {
836 s.virtstyle=VIRT_IPHASH;
837 } else if(!strncmp(virtstyle, "cidrhash", 8)) {
838 s.virtstyle=VIRT_CIDR;
839 if(strlen(virtstyle)<10) {
840 g_set_error(e, errdomain, CFILE_VALUE_INVALID, "Invalid value %s for parameter virtstyle in group %s: missing length", virtstyle, groups[i]);
841 g_array_free(retval, TRUE);
842 g_key_file_free(cfile);
845 s.cidrlen=strtol(virtstyle+8, NULL, 0);
847 g_set_error(e, errdomain, CFILE_VALUE_INVALID, "Invalid value %s for parameter virtstyle in group %s", virtstyle, groups[i]);
848 g_array_free(retval, TRUE);
849 g_key_file_free(cfile);
852 if(s.port && !do_oldstyle) {
853 g_warning("A port was specified, but oldstyle exports were not requested. This may not do what you expect.");
854 g_warning("Please read 'man 5 nbd-server' and search for oldstyle for more info");
857 s.virtstyle=VIRT_IPLIT;
859 /* Don't need to free this, it's not our string */
861 /* Don't append values for the [generic] group */
863 s.socket_family = AF_UNSPEC;
864 s.servename = groups[i];
866 append_serve(&s, retval);
873 if(s.flags & F_SDP) {
874 g_set_error(e, errdomain, CFILE_VALUE_UNSUPPORTED, "This nbd-server was built without support for SDP, yet group %s uses it", groups[i]);
875 g_array_free(retval, TRUE);
876 g_key_file_free(cfile);
882 g_set_error(e, errdomain, CFILE_NO_EXPORTS, "The config file does not specify any exports");
884 g_key_file_free(cfile);
889 * Signal handler for SIGCHLD
890 * @param s the signal we're handling (must be SIGCHLD, or something
893 void sigchld_handler(int s) {
898 while((pid=waitpid(-1, &status, WNOHANG)) > 0) {
899 if(WIFEXITED(status)) {
900 msg3(LOG_INFO, "Child exited with %d", WEXITSTATUS(status));
902 i=g_hash_table_lookup(children, &pid);
904 msg3(LOG_INFO, "SIGCHLD received for an unknown child with PID %ld", (long)pid);
906 DEBUG2("Removing %d from the list of children", pid);
907 g_hash_table_remove(children, &pid);
913 * Kill a child. Called from sigterm_handler::g_hash_table_foreach.
916 * @param value the value corresponding to the above key
917 * @param user_data a pointer which we always set to 1, so that we know what
920 void killchild(gpointer key, gpointer value, gpointer user_data) {
922 int *parent=user_data;
929 * Handle SIGTERM and dispatch it to our children
930 * @param s the signal we're handling (must be SIGTERM, or something
931 * is severely wrong).
933 void sigterm_handler(int s) {
936 g_hash_table_foreach(children, killchild, &parent);
946 * Detect the size of a file.
948 * @param fhandle An open filedescriptor
949 * @return the size of the file, or OFFT_MAX if detection was
952 off_t size_autodetect(int fhandle) {
955 struct stat stat_buf;
958 #ifdef HAVE_SYS_MOUNT_H
959 #ifdef HAVE_SYS_IOCTL_H
961 DEBUG("looking for export size with ioctl BLKGETSIZE64\n");
962 if (!ioctl(fhandle, BLKGETSIZE64, &bytes) && bytes) {
965 #endif /* BLKGETSIZE64 */
966 #endif /* HAVE_SYS_IOCTL_H */
967 #endif /* HAVE_SYS_MOUNT_H */
969 DEBUG("looking for fhandle size with fstat\n");
970 stat_buf.st_size = 0;
971 error = fstat(fhandle, &stat_buf);
973 if(stat_buf.st_size > 0)
974 return (off_t)stat_buf.st_size;
976 err("fstat failed: %m");
979 DEBUG("looking for fhandle size with lseek SEEK_END\n");
980 es = lseek(fhandle, (off_t)0, SEEK_END);
981 if (es > ((off_t)0)) {
984 DEBUG2("lseek failed: %d", errno==EBADF?1:(errno==ESPIPE?2:(errno==EINVAL?3:4)));
987 err("Could not find size of exported block device: %m");
992 * Get the file handle and offset, given an export offset.
994 * @param export An array of export files
995 * @param a The offset to get corresponding file/offset for
996 * @param fhandle [out] File descriptor
997 * @param foffset [out] Offset into fhandle
998 * @param maxbytes [out] Tells how many bytes can be read/written
999 * from fhandle starting at foffset (0 if there is no limit)
1000 * @return 0 on success, -1 on failure
1002 int get_filepos(GArray* export, off_t a, int* fhandle, off_t* foffset, size_t* maxbytes ) {
1003 /* Negative offset not allowed */
1007 /* Binary search for last file with starting offset <= a */
1010 int end = export->len - 1;
1011 while( start <= end ) {
1012 int mid = (start + end) / 2;
1013 fi = g_array_index(export, FILE_INFO, mid);
1014 if( fi.startoff < a ) {
1016 } else if( fi.startoff > a ) {
1024 /* end should never go negative, since first startoff is 0 and a >= 0 */
1027 fi = g_array_index(export, FILE_INFO, end);
1028 *fhandle = fi.fhandle;
1029 *foffset = a - fi.startoff;
1031 if( end+1 < export->len ) {
1032 FILE_INFO fi_next = g_array_index(export, FILE_INFO, end+1);
1033 *maxbytes = fi_next.startoff - a;
1040 * seek to a position in a file, with error handling.
1041 * @param handle a filedescriptor
1042 * @param a position to seek to
1043 * @todo get rid of this; lastpoint is a global variable right now, but it
1044 * shouldn't be. If we pass it on as a parameter, that makes things a *lot*
1047 void myseek(int handle,off_t a) {
1048 if (lseek(handle, a, SEEK_SET) < 0) {
1049 err("Can not seek locally!\n");
1054 * Write an amount of bytes at a given offset to the right file. This
1055 * abstracts the write-side of the multiple file option.
1057 * @param a The offset where the write should start
1058 * @param buf The buffer to write from
1059 * @param len The length of buf
1060 * @param client The client we're serving for
1061 * @return The number of bytes actually written, or -1 in case of an error
1063 ssize_t rawexpwrite(off_t a, char *buf, size_t len, CLIENT *client) {
1069 if(get_filepos(client->export, a, &fhandle, &foffset, &maxbytes))
1071 if(maxbytes && len > maxbytes)
1074 DEBUG4("(WRITE to fd %d offset %llu len %u), ", fhandle, foffset, len);
1076 myseek(fhandle, foffset);
1077 retval = write(fhandle, buf, len);
1078 if(client->server->flags & F_SYNC) {
1085 * Call rawexpwrite repeatedly until all data has been written.
1086 * @return 0 on success, nonzero on failure
1088 int rawexpwrite_fully(off_t a, char *buf, size_t len, CLIENT *client) {
1091 while(len > 0 && (ret=rawexpwrite(a, buf, len, client)) > 0 ) {
1096 return (ret < 0 || len != 0);
1100 * Read an amount of bytes at a given offset from the right file. This
1101 * abstracts the read-side of the multiple files option.
1103 * @param a The offset where the read should start
1104 * @param buf A buffer to read into
1105 * @param len The size of buf
1106 * @param client The client we're serving for
1107 * @return The number of bytes actually read, or -1 in case of an
1110 ssize_t rawexpread(off_t a, char *buf, size_t len, CLIENT *client) {
1115 if(get_filepos(client->export, a, &fhandle, &foffset, &maxbytes))
1117 if(maxbytes && len > maxbytes)
1120 DEBUG4("(READ from fd %d offset %llu len %u), ", fhandle, foffset, len);
1122 myseek(fhandle, foffset);
1123 return read(fhandle, buf, len);
1127 * Call rawexpread repeatedly until all data has been read.
1128 * @return 0 on success, nonzero on failure
1130 int rawexpread_fully(off_t a, char *buf, size_t len, CLIENT *client) {
1133 while(len > 0 && (ret=rawexpread(a, buf, len, client)) > 0 ) {
1138 return (ret < 0 || len != 0);
1142 * Read an amount of bytes at a given offset from the right file. This
1143 * abstracts the read-side of the copyonwrite stuff, and calls
1144 * rawexpread() with the right parameters to do the actual work.
1145 * @param a The offset where the read should start
1146 * @param buf A buffer to read into
1147 * @param len The size of buf
1148 * @param client The client we're going to read for
1149 * @return 0 on success, nonzero on failure
1151 int expread(off_t a, char *buf, size_t len, CLIENT *client) {
1152 off_t rdlen, offset;
1153 off_t mapcnt, mapl, maph, pagestart;
1155 if (!(client->server->flags & F_COPYONWRITE))
1156 return(rawexpread_fully(a, buf, len, client));
1157 DEBUG3("Asked to read %d bytes at %llu.\n", len, (unsigned long long)a);
1159 mapl=a/DIFFPAGESIZE; maph=(a+len-1)/DIFFPAGESIZE;
1161 for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
1162 pagestart=mapcnt*DIFFPAGESIZE;
1164 rdlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
1165 len : (size_t)DIFFPAGESIZE-offset;
1166 if (client->difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
1167 DEBUG3("Page %llu is at %lu\n", (unsigned long long)mapcnt,
1168 (unsigned long)(client->difmap[mapcnt]));
1169 myseek(client->difffile, client->difmap[mapcnt]*DIFFPAGESIZE+offset);
1170 if (read(client->difffile, buf, rdlen) != rdlen) return -1;
1171 } else { /* the block is not there */
1172 DEBUG2("Page %llu is not here, we read the original one\n",
1173 (unsigned long long)mapcnt);
1174 if(rawexpread_fully(a, buf, rdlen, client)) return -1;
1176 len-=rdlen; a+=rdlen; buf+=rdlen;
1182 * Write an amount of bytes at a given offset to the right file. This
1183 * abstracts the write-side of the copyonwrite option, and calls
1184 * rawexpwrite() with the right parameters to do the actual work.
1186 * @param a The offset where the write should start
1187 * @param buf The buffer to write from
1188 * @param len The length of buf
1189 * @param client The client we're going to write for.
1190 * @return 0 on success, nonzero on failure
1192 int expwrite(off_t a, char *buf, size_t len, CLIENT *client) {
1193 char pagebuf[DIFFPAGESIZE];
1194 off_t mapcnt,mapl,maph;
1199 if (!(client->server->flags & F_COPYONWRITE))
1200 return(rawexpwrite_fully(a, buf, len, client));
1201 DEBUG3("Asked to write %d bytes at %llu.\n", len, (unsigned long long)a);
1203 mapl=a/DIFFPAGESIZE ; maph=(a+len-1)/DIFFPAGESIZE ;
1205 for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
1206 pagestart=mapcnt*DIFFPAGESIZE ;
1207 offset=a-pagestart ;
1208 wrlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
1209 len : (size_t)DIFFPAGESIZE-offset;
1211 if (client->difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
1212 DEBUG3("Page %llu is at %lu\n", (unsigned long long)mapcnt,
1213 (unsigned long)(client->difmap[mapcnt])) ;
1214 myseek(client->difffile,
1215 client->difmap[mapcnt]*DIFFPAGESIZE+offset);
1216 if (write(client->difffile, buf, wrlen) != wrlen) return -1 ;
1217 } else { /* the block is not there */
1218 myseek(client->difffile,client->difffilelen*DIFFPAGESIZE) ;
1219 client->difmap[mapcnt]=(client->server->flags&F_SPARSE)?mapcnt:client->difffilelen++;
1220 DEBUG3("Page %llu is not here, we put it at %lu\n",
1221 (unsigned long long)mapcnt,
1222 (unsigned long)(client->difmap[mapcnt]));
1223 rdlen=DIFFPAGESIZE ;
1224 if (rawexpread_fully(pagestart, pagebuf, rdlen, client))
1226 memcpy(pagebuf+offset,buf,wrlen) ;
1227 if (write(client->difffile, pagebuf, DIFFPAGESIZE) !=
1231 len-=wrlen ; a+=wrlen ; buf+=wrlen ;
1237 * Do the initial negotiation.
1239 * @param client The client we're negotiating with.
1241 CLIENT* negotiate(int net, CLIENT *client, GArray* servers) {
1244 uint32_t flags = NBD_FLAG_HAS_FLAGS;
1245 uint16_t smallflags = 0;
1248 memset(zeros, '\0', sizeof(zeros));
1249 if(!client || !client->modern) {
1251 if (write(net, INIT_PASSWD, 8) < 0) {
1252 err_nonfatal("Negotiation failed: %m");
1256 if(!client || client->modern) {
1258 magic = htonll(opts_magic);
1261 magic = htonll(cliserv_magic);
1263 if (write(net, &magic, sizeof(magic)) < 0) {
1264 err_nonfatal("Negotiation failed: %m");
1278 err("programmer error");
1279 if (write(net, &smallflags, sizeof(uint16_t)) < 0)
1280 err("Negotiation failed: %m");
1281 if (read(net, &reserved, sizeof(reserved)) < 0)
1282 err("Negotiation failed: %m");
1283 if (read(net, &magic, sizeof(magic)) < 0)
1284 err("Negotiation failed: %m");
1285 magic = ntohll(magic);
1286 if(magic != opts_magic) {
1290 if (read(net, &opt, sizeof(opt)) < 0)
1291 err("Negotiation failed: %m");
1293 if(opt != NBD_OPT_EXPORT_NAME) {
1297 if (read(net, &namelen, sizeof(namelen)) < 0)
1298 err("Negotiation failed: %m");
1299 namelen = ntohl(namelen);
1300 name = malloc(namelen+1);
1302 if (read(net, name, namelen) < 0)
1303 err("Negotiation failed: %m");
1304 for(i=0; i<servers->len; i++) {
1305 SERVER* serve = &(g_array_index(servers, SERVER, i));
1306 if(!strcmp(serve->servename, name)) {
1307 CLIENT* client = g_new0(CLIENT, 1);
1308 client->server = serve;
1309 client->exportsize = OFFT_MAX;
1311 client->modern = TRUE;
1320 size_host = htonll((u64)(client->exportsize));
1321 if (write(net, &size_host, 8) < 0)
1322 err("Negotiation failed: %m");
1323 if (client->server->flags & F_READONLY)
1324 flags |= NBD_FLAG_READ_ONLY;
1325 if (!client->modern) {
1327 flags = htonl(flags);
1328 if (write(client->net, &flags, 4) < 0)
1329 err("Negotiation failed: %m");
1332 smallflags = (uint16_t)(flags & ~((uint16_t)0));
1333 smallflags = htons(smallflags);
1334 if (write(client->net, &smallflags, sizeof(smallflags)) < 0) {
1335 err("Negotiation failed: %m");
1339 if (write(client->net, zeros, 124) < 0)
1340 err("Negotiation failed: %m");
1344 /** sending macro. */
1345 #define SEND(net,reply) writeit( net, &reply, sizeof( reply ));
1347 #define ERROR(client,reply,errcode) { reply.error = htonl(errcode); SEND(client->net,reply); reply.error = 0; }
1349 * Serve a file to a single client.
1351 * @todo This beast needs to be split up in many tiny little manageable
1352 * pieces. Preferably with a chainsaw.
1354 * @param client The client we're going to serve to.
1355 * @return when the client disconnects
1357 int mainloop(CLIENT *client) {
1358 struct nbd_request request;
1359 struct nbd_reply reply;
1360 gboolean go_on=TRUE;
1364 negotiate(client->net, client, NULL);
1365 DEBUG("Entering request loop!\n");
1366 reply.magic = htonl(NBD_REPLY_MAGIC);
1378 readit(client->net, &request, sizeof(request));
1379 request.from = ntohll(request.from);
1380 request.type = ntohl(request.type);
1382 if (request.type==NBD_CMD_DISC) {
1383 msg2(LOG_INFO, "Disconnect request received.");
1384 if (client->server->flags & F_COPYONWRITE) {
1385 if (client->difmap) g_free(client->difmap) ;
1386 close(client->difffile);
1387 unlink(client->difffilename);
1388 free(client->difffilename);
1394 len = ntohl(request.len);
1396 if (request.magic != htonl(NBD_REQUEST_MAGIC))
1397 err("Not enough magic.");
1398 if (len > BUFSIZE - sizeof(struct nbd_reply)) {
1399 currlen = BUFSIZE - sizeof(struct nbd_reply);
1400 msg2(LOG_INFO, "oversized request (this is not a problem)");
1405 printf("%s from %llu (%llu) len %d, ", request.type ? "WRITE" :
1406 "READ", (unsigned long long)request.from,
1407 (unsigned long long)request.from / 512, len);
1409 memcpy(reply.handle, request.handle, sizeof(reply.handle));
1410 if ((request.from + len) > (OFFT_MAX)) {
1411 DEBUG("[Number too large!]");
1412 ERROR(client, reply, EINVAL);
1416 if (((ssize_t)((off_t)request.from + len) > client->exportsize)) {
1418 ERROR(client, reply, EINVAL);
1422 if (request.type==NBD_CMD_WRITE) {
1423 DEBUG("wr: net->buf, ");
1425 readit(client->net, buf, currlen);
1426 DEBUG("buf->exp, ");
1427 if ((client->server->flags & F_READONLY) ||
1428 (client->server->flags & F_AUTOREADONLY)) {
1429 DEBUG("[WRITE to READONLY!]");
1430 ERROR(client, reply, EPERM);
1433 if (expwrite(request.from, buf, len, client)) {
1434 DEBUG("Write failed: %m" );
1435 ERROR(client, reply, errno);
1438 SEND(client->net, reply);
1441 currlen = (len < BUFSIZE) ? len : BUFSIZE;
1447 DEBUG("exp->buf, ");
1448 memcpy(buf, &reply, sizeof(struct nbd_reply));
1449 p = buf + sizeof(struct nbd_reply);
1450 writelen = currlen + sizeof(struct nbd_reply);
1452 if (expread(request.from, p, currlen, client)) {
1453 DEBUG("Read failed: %m");
1454 ERROR(client, reply, errno);
1458 DEBUG("buf->net, ");
1459 writeit(client->net, buf, writelen);
1461 currlen = (len < BUFSIZE) ? len : BUFSIZE;
1471 * Set up client export array, which is an array of FILE_INFO.
1472 * Also, split a single exportfile into multiple ones, if that was asked.
1473 * @param client information on the client which we want to setup export for
1475 void setupexport(CLIENT* client) {
1477 off_t laststartoff = 0, lastsize = 0;
1478 int multifile = (client->server->flags & F_MULTIFILE);
1480 client->export = g_array_new(TRUE, TRUE, sizeof(FILE_INFO));
1482 /* If multi-file, open as many files as we can.
1483 * If not, open exactly one file.
1484 * Calculate file sizes as we go to get total size. */
1488 gchar* error_string;
1489 mode_t mode = (client->server->flags & F_READONLY) ? O_RDONLY : O_RDWR;
1492 tmpname=g_strdup_printf("%s.%d", client->exportname, i);
1494 tmpname=g_strdup(client->exportname);
1496 DEBUG2( "Opening %s\n", tmpname );
1497 fi.fhandle = open(tmpname, mode);
1498 if(fi.fhandle == -1 && mode == O_RDWR) {
1499 /* Try again because maybe media was read-only */
1500 fi.fhandle = open(tmpname, O_RDONLY);
1501 if(fi.fhandle != -1) {
1502 /* Opening the base file in copyonwrite mode is
1504 if(!(client->server->flags & F_COPYONWRITE)) {
1505 client->server->flags |= F_AUTOREADONLY;
1506 client->server->flags |= F_READONLY;
1510 if(fi.fhandle == -1) {
1511 if(multifile && i>0)
1513 error_string=g_strdup_printf(
1514 "Could not open exported file %s: %%m",
1518 fi.startoff = laststartoff + lastsize;
1519 g_array_append_val(client->export, fi);
1522 /* Starting offset and size of this file will be used to
1523 * calculate starting offset of next file */
1524 laststartoff = fi.startoff;
1525 lastsize = size_autodetect(fi.fhandle);
1531 /* Set export size to total calculated size */
1532 client->exportsize = laststartoff + lastsize;
1534 /* Export size may be overridden */
1535 if(client->server->expected_size) {
1536 /* desired size must be <= total calculated size */
1537 if(client->server->expected_size > client->exportsize) {
1538 err("Size of exported file is too big\n");
1541 client->exportsize = client->server->expected_size;
1544 msg3(LOG_INFO, "Size of exported file/device is %llu", (unsigned long long)client->exportsize);
1546 msg3(LOG_INFO, "Total number of files: %d", i);
1550 int copyonwrite_prepare(CLIENT* client) {
1552 if ((client->difffilename = malloc(1024))==NULL)
1553 err("Failed to allocate string for diff file name");
1554 snprintf(client->difffilename, 1024, "%s-%s-%d.diff",client->exportname,client->clientname,
1556 client->difffilename[1023]='\0';
1557 msg3(LOG_INFO,"About to create map and diff file %s",client->difffilename) ;
1558 client->difffile=open(client->difffilename,O_RDWR | O_CREAT | O_TRUNC,0600) ;
1559 if (client->difffile<0) err("Could not create diff file (%m)") ;
1560 if ((client->difmap=calloc(client->exportsize/DIFFPAGESIZE,sizeof(u32)))==NULL)
1561 err("Could not allocate memory") ;
1562 for (i=0;i<client->exportsize/DIFFPAGESIZE;i++) client->difmap[i]=(u32)-1 ;
1568 * Run a command. This is used for the ``prerun'' and ``postrun'' config file
1571 * @param command the command to be ran. Read from the config file
1572 * @param file the file name we're about to export
1574 int do_run(gchar* command, gchar* file) {
1578 if(command && *command) {
1579 cmd = g_strdup_printf(command, file);
1587 * Serve a connection.
1589 * @todo allow for multithreading, perhaps use libevent. Not just yet, though;
1590 * follow the road map.
1592 * @param client a connected client
1594 void serveconnection(CLIENT *client) {
1595 if(do_run(client->server->prerun, client->exportname)) {
1598 setupexport(client);
1600 if (client->server->flags & F_COPYONWRITE) {
1601 copyonwrite_prepare(client);
1604 setmysockopt(client->net);
1607 do_run(client->server->postrun, client->exportname);
1611 * Find the name of the file we have to serve. This will use g_strdup_printf
1612 * to put the IP address of the client inside a filename containing
1613 * "%s" (in the form as specified by the "virtstyle" option). That name
1614 * is then written to client->exportname.
1616 * @param net A socket connected to an nbd client
1617 * @param client information about the client. The IP address in human-readable
1618 * format will be written to a new char* buffer, the address of which will be
1619 * stored in client->clientname.
1621 void set_peername(int net, CLIENT *client) {
1622 struct sockaddr_storage addrin;
1623 struct sockaddr_storage netaddr;
1624 struct sockaddr_in *netaddr4 = NULL;
1625 struct sockaddr_in6 *netaddr6 = NULL;
1626 size_t addrinlen = sizeof( addrin );
1627 struct addrinfo hints;
1628 struct addrinfo *ai = NULL;
1629 char peername[NI_MAXHOST];
1630 char netname[NI_MAXHOST];
1636 if (getpeername(net, (struct sockaddr *) &addrin, (socklen_t *)&addrinlen) < 0)
1637 err("getsockname failed: %m");
1639 getnameinfo((struct sockaddr *)&addrin, (socklen_t)addrinlen,
1640 peername, sizeof (peername), NULL, 0, NI_NUMERICHOST);
1642 memset(&hints, '\0', sizeof (hints));
1643 hints.ai_flags = AI_ADDRCONFIG;
1644 e = getaddrinfo(peername, NULL, &hints, &ai);
1647 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
1652 switch(client->server->virtstyle) {
1654 client->exportname=g_strdup(client->server->exportname);
1657 for(i=0;i<strlen(peername);i++) {
1658 if(peername[i]=='.') {
1663 client->exportname=g_strdup_printf(client->server->exportname, peername);
1666 memcpy(&netaddr, &addrin, addrinlen);
1667 if(ai->ai_family == AF_INET) {
1668 netaddr4 = (struct sockaddr_in *)&netaddr;
1669 (netaddr4->sin_addr).s_addr>>=32-(client->server->cidrlen);
1670 (netaddr4->sin_addr).s_addr<<=32-(client->server->cidrlen);
1672 getnameinfo((struct sockaddr *) netaddr4, (socklen_t) addrinlen,
1673 netname, sizeof (netname), NULL, 0, NI_NUMERICHOST);
1674 tmp=g_strdup_printf("%s/%s", netname, peername);
1675 }else if(ai->ai_family == AF_INET6) {
1676 netaddr6 = (struct sockaddr_in6 *)&netaddr;
1678 shift = 128-(client->server->cidrlen);
1680 while(shift >= 32) {
1681 ((netaddr6->sin6_addr).s6_addr32[i])=0;
1685 (netaddr6->sin6_addr).s6_addr32[i]>>=shift;
1686 (netaddr6->sin6_addr).s6_addr32[i]<<=shift;
1688 getnameinfo((struct sockaddr *)netaddr6, (socklen_t)addrinlen,
1689 netname, sizeof(netname), NULL, 0, NI_NUMERICHOST);
1690 tmp=g_strdup_printf("%s/%s", netname, peername);
1694 client->exportname=g_strdup_printf(client->server->exportname, tmp);
1700 msg4(LOG_INFO, "connect from %s, assigned file is %s",
1701 peername, client->exportname);
1702 client->clientname=g_strdup(peername);
1707 * @param data a pointer to pid_t which should be freed
1709 void destroy_pid_t(gpointer data) {
1714 * Loop through the available servers, and serve them. Never returns.
1716 int serveloop(GArray* servers) {
1717 struct sockaddr_storage addrin;
1718 socklen_t addrinlen=sizeof(addrin);
1726 * Set up the master fd_set. The set of descriptors we need
1727 * to select() for never changes anyway and it buys us a *lot*
1728 * of time to only build this once. However, if we ever choose
1729 * to not fork() for clients anymore, we may have to revisit
1734 for(i=0;i<servers->len;i++) {
1735 if((sock=(g_array_index(servers, SERVER, i)).socket)) {
1736 FD_SET(sock, &mset);
1737 max=sock>max?sock:max;
1741 FD_SET(modernsock, &mset);
1742 max=modernsock>max?modernsock:max;
1745 CLIENT *client = NULL;
1748 memcpy(&rset, &mset, sizeof(fd_set));
1749 if(select(max+1, &rset, NULL, NULL, NULL)>0) {
1754 if(FD_ISSET(modernsock, &rset)) {
1755 if((net=accept(modernsock, (struct sockaddr *) &addrin, &addrinlen)) < 0)
1757 client = negotiate(net, NULL, servers);
1759 err_nonfatal("negotiation failed");
1763 serve = client->server;
1765 for(i=0;i<servers->len && !net;i++) {
1766 serve=&(g_array_index(servers, SERVER, i));
1767 if(FD_ISSET(serve->socket, &rset)) {
1768 if ((net=accept(serve->socket, (struct sockaddr *) &addrin, &addrinlen)) < 0)
1775 if(serve->max_connections > 0 &&
1776 g_hash_table_size(children) >= serve->max_connections) {
1777 msg2(LOG_INFO, "Max connections reached");
1781 if((sock_flags = fcntl(net, F_GETFL, 0))==-1) {
1782 err("fcntl F_GETFL");
1784 if(fcntl(net, F_SETFL, sock_flags &~O_NONBLOCK)==-1) {
1785 err("fcntl F_SETFL ~O_NONBLOCK");
1788 client = g_new0(CLIENT, 1);
1789 client->server=serve;
1790 client->exportsize=OFFT_MAX;
1793 set_peername(net, client);
1794 if (!authorized_client(client)) {
1795 msg2(LOG_INFO,"Unauthorized client") ;
1799 msg2(LOG_INFO,"Authorized client") ;
1800 pid=g_malloc(sizeof(pid_t));
1802 if ((*pid=fork())<0) {
1803 msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ;
1807 if (*pid>0) { /* parent */
1809 g_hash_table_insert(children, pid, pid);
1813 g_hash_table_destroy(children);
1814 for(i=0;i<servers->len;i++) {
1815 serve=&g_array_index(servers, SERVER, i);
1816 close(serve->socket);
1818 /* FALSE does not free the
1819 actual data. This is required,
1820 because the client has a
1821 direct reference into that
1822 data, and otherwise we get a
1824 g_array_free(servers, FALSE);
1826 msg2(LOG_INFO,"Starting to serve");
1827 serveconnection(client);
1834 void dosockopts(int socket) {
1842 /* lose the pesky "Address already in use" error message */
1843 if (setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
1844 err("setsockopt SO_REUSEADDR");
1846 if (setsockopt(socket,SOL_SOCKET,SO_KEEPALIVE,&yes,sizeof(int)) == -1) {
1847 err("setsockopt SO_KEEPALIVE");
1850 /* make the listening socket non-blocking */
1851 if ((sock_flags = fcntl(socket, F_GETFL, 0)) == -1) {
1852 err("fcntl F_GETFL");
1854 if (fcntl(socket, F_SETFL, sock_flags | O_NONBLOCK) == -1) {
1855 err("fcntl F_SETFL O_NONBLOCK");
1860 * Connect a server's socket.
1862 * @param serve the server we want to connect.
1864 int setup_serve(SERVER *serve) {
1865 struct addrinfo hints;
1866 struct addrinfo *ai = NULL;
1871 return serve->servename ? 1 : 0;
1873 memset(&hints,'\0',sizeof(hints));
1874 hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG | AI_NUMERICSERV;
1875 hints.ai_socktype = SOCK_STREAM;
1876 hints.ai_family = serve->socket_family;
1878 port = g_strdup_printf ("%d", serve->port);
1882 e = getaddrinfo(serve->listenaddr,port,&hints,&ai);
1887 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
1893 if(serve->socket_family == AF_UNSPEC)
1894 serve->socket_family = ai->ai_family;
1897 if ((serve->flags) && F_SDP) {
1898 if (ai->ai_family == AF_INET)
1899 ai->ai_family = AF_INET_SDP;
1900 else (ai->ai_family == AF_INET6)
1901 ai->ai_family = AF_INET6_SDP;
1904 if ((serve->socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0)
1907 dosockopts(serve->socket);
1909 DEBUG("Waiting for connections... bind, ");
1910 e = bind(serve->socket, ai->ai_addr, ai->ai_addrlen);
1911 if (e != 0 && errno != EADDRINUSE)
1914 if (listen(serve->socket, 1) < 0)
1918 if(serve->servename) {
1925 void open_modern(void) {
1926 struct addrinfo hints;
1927 struct addrinfo* ai = NULL;
1931 memset(&hints, '\0', sizeof(hints));
1932 hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
1933 hints.ai_socktype = SOCK_STREAM;
1934 hints.ai_family = AF_UNSPEC;
1935 hints.ai_protocol = IPPROTO_TCP;
1936 e = getaddrinfo(modern_listen, NBD_DEFAULT_PORT, &hints, &ai);
1938 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
1941 if((modernsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))<0) {
1945 dosockopts(modernsock);
1947 if(bind(modernsock, ai->ai_addr, ai->ai_addrlen)) {
1950 if(listen(modernsock, 10) <0) {
1958 * Connect our servers.
1960 void setup_servers(GArray* servers) {
1962 struct sigaction sa;
1965 for(i=0;i<servers->len;i++) {
1966 want_modern |= setup_serve(&(g_array_index(servers, SERVER, i)));
1971 children=g_hash_table_new_full(g_int_hash, g_int_equal, NULL, destroy_pid_t);
1973 sa.sa_handler = sigchld_handler;
1974 sigemptyset(&sa.sa_mask);
1975 sa.sa_flags = SA_RESTART;
1976 if(sigaction(SIGCHLD, &sa, NULL) == -1)
1977 err("sigaction: %m");
1978 sa.sa_handler = sigterm_handler;
1979 sigemptyset(&sa.sa_mask);
1980 sa.sa_flags = SA_RESTART;
1981 if(sigaction(SIGTERM, &sa, NULL) == -1)
1982 err("sigaction: %m");
1986 * Go daemon (unless we specified at compile time that we didn't want this)
1987 * @param serve the first server of our configuration. If its port is zero,
1988 * then do not daemonize, because we're doing inetd then. This parameter
1989 * is only used to create a PID file of the form
1990 * /var/run/nbd-server.<port>.pid; it's not modified in any way.
1992 #if !defined(NODAEMON) && !defined(NOFORK)
1993 void daemonize(SERVER* serve) {
1996 if(serve && !(serve->port)) {
2002 if(!*pidftemplate) {
2004 strncpy(pidftemplate, "/var/run/nbd-server.%d.pid", 255);
2006 strncpy(pidftemplate, "/var/run/nbd-server.pid", 255);
2009 snprintf(pidfname, 255, pidftemplate, serve ? serve->port : 0);
2010 pidf=fopen(pidfname, "w");
2012 fprintf(pidf,"%d\n", (int)getpid());
2016 fprintf(stderr, "Not fatal; continuing");
2020 #define daemonize(serve)
2021 #endif /* !defined(NODAEMON) && !defined(NOFORK) */
2024 * Everything beyond this point (in the file) is run in non-daemon mode.
2025 * The stuff above daemonize() isn't.
2028 void serve_err(SERVER* serve, const char* msg) G_GNUC_NORETURN;
2030 void serve_err(SERVER* serve, const char* msg) {
2031 g_message("Export of %s on port %d failed:", serve->exportname,
2037 * Set up user-ID and/or group-ID
2039 void dousers(void) {
2044 gr=getgrnam(rungroup);
2046 str = g_strdup_printf("Invalid group name: %s", rungroup);
2049 if(setgid(gr->gr_gid)<0) {
2050 err("Could not set GID: %m");
2054 pw=getpwnam(runuser);
2056 str = g_strdup_printf("Invalid user name: %s", runuser);
2059 if(setuid(pw->pw_uid)<0) {
2060 err("Could not set UID: %m");
2066 void glib_message_syslog_redirect(const gchar *log_domain,
2067 GLogLevelFlags log_level,
2068 const gchar *message,
2071 int level=LOG_DEBUG;
2075 case G_LOG_FLAG_FATAL:
2076 case G_LOG_LEVEL_CRITICAL:
2077 case G_LOG_LEVEL_ERROR:
2080 case G_LOG_LEVEL_WARNING:
2083 case G_LOG_LEVEL_MESSAGE:
2084 case G_LOG_LEVEL_INFO:
2087 case G_LOG_LEVEL_DEBUG:
2092 syslog(level, "%s", message);
2097 * Main entry point...
2099 int main(int argc, char *argv[]) {
2104 if (sizeof( struct nbd_request )!=28) {
2105 fprintf(stderr,"Bad size of structure. Alignment problems?\n");
2106 exit(EXIT_FAILURE) ;
2109 memset(pidftemplate, '\0', 256);
2112 config_file_pos = g_strdup(CFILE);
2113 serve=cmdline(argc, argv);
2114 servers = parse_cfile(config_file_pos, &err);
2117 serve->socket_family = AF_UNSPEC;
2119 append_serve(serve, servers);
2121 if (!(serve->port)) {
2124 /* You really should define ISSERVER if you're going to use
2125 * inetd mode, but if you don't, closing stdout and stderr
2126 * (which inetd had connected to the client socket) will let it
2130 open("/dev/null", O_WRONLY);
2131 open("/dev/null", O_WRONLY);
2132 g_log_set_default_handler( glib_message_syslog_redirect, NULL );
2134 client=g_malloc(sizeof(CLIENT));
2135 client->server=serve;
2137 client->exportsize=OFFT_MAX;
2138 set_peername(0,client);
2139 serveconnection(client);
2144 if(!servers || !servers->len) {
2145 if(err && !(err->domain == g_quark_from_string("parse_cfile")
2146 && err->code == CFILE_NOTFOUND)) {
2147 g_warning("Could not parse config file: %s",
2148 err ? err->message : "Unknown error");
2152 g_warning("Specifying an export on the command line is deprecated.");
2153 g_warning("Please use a configuration file instead.");
2156 if((!serve) && (!servers||!servers->len)) {
2157 g_message("No configured exports; quitting.");
2161 setup_servers(servers);