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 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 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 = serve->socket;
603 serve->socket_family = serve->socket_family;
604 serve->cidrlen = s->cidrlen;
607 serve->prerun = g_strdup(s->prerun);
610 serve->postrun = g_strdup(s->postrun);
613 serve->servename = g_strdup(s->servename);
615 serve->max_connections = s->max_connections;
621 * append new server to array
623 * @param a server array
624 * @return 0 success, -1 error
626 int append_serve(SERVER *s, GArray *a) {
628 struct addrinfo hints;
629 struct addrinfo *ai = NULL;
630 struct addrinfo *rp = NULL;
631 char host[NI_MAXHOST];
637 err("Invalid parsing server");
641 port = g_strdup_printf("%d", s->port);
643 memset(&hints,'\0',sizeof(hints));
644 hints.ai_family = AF_UNSPEC;
645 hints.ai_socktype = SOCK_STREAM;
646 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
647 hints.ai_protocol = IPPROTO_TCP;
649 e = getaddrinfo(s->listenaddr, port, &hints, &ai);
655 for (rp = ai; rp != NULL; rp = rp->ai_next) {
656 e = getnameinfo(rp->ai_addr, rp->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
658 if (e != 0) { // error
659 fprintf(stderr, "getnameinfo: %s\n", gai_strerror(e));
663 // duplicate server and set listenaddr to resolved IP address
666 ns->listenaddr = g_strdup(host);
667 ns->socket_family = rp->ai_family;
668 g_array_append_val(a, *ns);
676 fprintf(stderr, "getaddrinfo failed on listen host/address: %s (%s)\n", s->listenaddr ? s->listenaddr : "any", gai_strerror(e));
687 * Parse the config file.
689 * @param f the name of the config file
690 * @param e a GError. @see CFILE_ERRORS for what error values this function can
692 * @return a Array of SERVER* pointers, If the config file is empty or does not
693 * exist, returns an empty GHashTable; if the config file contains an
694 * error, returns NULL, and e is set appropriately
696 GArray* parse_cfile(gchar* f, GError** e) {
697 const char* DEFAULT_ERROR = "Could not parse %s in group %s: %s";
698 const char* MISSING_REQUIRED_ERROR = "Could not find required value %s in group %s: %s";
700 gchar *virtstyle=NULL;
702 { "exportname", TRUE, PARAM_STRING, NULL, 0 },
703 { "port", TRUE, PARAM_INT, NULL, 0 },
704 { "authfile", FALSE, PARAM_STRING, NULL, 0 },
705 { "filesize", FALSE, PARAM_INT, NULL, 0 },
706 { "virtstyle", FALSE, PARAM_STRING, NULL, 0 },
707 { "prerun", FALSE, PARAM_STRING, NULL, 0 },
708 { "postrun", FALSE, PARAM_STRING, NULL, 0 },
709 { "readonly", FALSE, PARAM_BOOL, NULL, F_READONLY },
710 { "multifile", FALSE, PARAM_BOOL, NULL, F_MULTIFILE },
711 { "copyonwrite", FALSE, PARAM_BOOL, NULL, F_COPYONWRITE },
712 { "sparse_cow", FALSE, PARAM_BOOL, NULL, F_SPARSE },
713 { "sdp", FALSE, PARAM_BOOL, NULL, F_SDP },
714 { "sync", FALSE, PARAM_BOOL, NULL, F_SYNC },
715 { "listenaddr", FALSE, PARAM_STRING, NULL, 0 },
716 { "maxconnections", FALSE, PARAM_INT, NULL, 0 },
718 const int lp_size=sizeof(lp)/sizeof(PARAM);
720 { "user", FALSE, PARAM_STRING, &runuser, 0 },
721 { "group", FALSE, PARAM_STRING, &rungroup, 0 },
722 { "oldstyle", FALSE, PARAM_BOOL, &do_oldstyle, 1 },
723 { "listenaddr", FALSE, PARAM_STRING, &modern_listen, 0 },
726 int p_size=sizeof(gp)/sizeof(PARAM);
729 const char *err_msg=NULL;
738 errdomain = g_quark_from_string("parse_cfile");
739 cfile = g_key_file_new();
740 retval = g_array_new(FALSE, TRUE, sizeof(SERVER));
741 if(!g_key_file_load_from_file(cfile, f, G_KEY_FILE_KEEP_COMMENTS |
742 G_KEY_FILE_KEEP_TRANSLATIONS, &err)) {
743 g_set_error(e, errdomain, CFILE_NOTFOUND, "Could not open config file %s.", f);
744 g_key_file_free(cfile);
747 startgroup = g_key_file_get_start_group(cfile);
748 if(!startgroup || strcmp(startgroup, "generic")) {
749 g_set_error(e, errdomain, CFILE_MISSING_GENERIC, "Config file does not contain the [generic] group!");
750 g_key_file_free(cfile);
753 groups = g_key_file_get_groups(cfile, NULL);
754 for(i=0;groups[i];i++) {
755 memset(&s, '\0', sizeof(SERVER));
756 lp[0].target=&(s.exportname);
757 lp[1].target=&(s.port);
758 lp[2].target=&(s.authname);
759 lp[3].target=&(s.expected_size);
760 lp[4].target=&(virtstyle);
761 lp[5].target=&(s.prerun);
762 lp[6].target=&(s.postrun);
763 lp[7].target=lp[8].target=lp[9].target=
764 lp[10].target=lp[11].target=
765 lp[12].target=&(s.flags);
766 lp[13].target=&(s.listenaddr);
767 lp[14].target=&(s.max_connections);
769 /* After the [generic] group, start parsing exports */
774 for(j=0;j<p_size;j++) {
775 g_assert(p[j].target != NULL);
776 g_assert(p[j].ptype==PARAM_INT||p[j].ptype==PARAM_STRING||p[j].ptype==PARAM_BOOL);
779 *((gint*)p[j].target) =
780 g_key_file_get_integer(cfile,
786 *((gchar**)p[j].target) =
787 g_key_file_get_string(cfile,
793 value = g_key_file_get_boolean(cfile,
795 p[j].paramname, &err);
798 *((gint*)p[j].target) |= p[j].flagval;
800 *((gint*)p[j].target) &= ~(p[j].flagval);
805 if(!strcmp(p[j].paramname, "port") && !strcmp(p[j].target, NBD_DEFAULT_PORT)) {
806 g_set_error(e, errdomain, CFILE_INCORRECT_PORT, "Config file specifies default port for oldstyle export");
807 g_key_file_free(cfile);
811 if(err->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
813 /* Ignore not-found error for optional values */
817 err_msg = MISSING_REQUIRED_ERROR;
820 err_msg = DEFAULT_ERROR;
822 g_set_error(e, errdomain, CFILE_VALUE_INVALID, err_msg, p[j].paramname, groups[i], err->message);
823 g_array_free(retval, TRUE);
825 g_key_file_free(cfile);
830 if(!strncmp(virtstyle, "none", 4)) {
831 s.virtstyle=VIRT_NONE;
832 } else if(!strncmp(virtstyle, "ipliteral", 9)) {
833 s.virtstyle=VIRT_IPLIT;
834 } else if(!strncmp(virtstyle, "iphash", 6)) {
835 s.virtstyle=VIRT_IPHASH;
836 } else if(!strncmp(virtstyle, "cidrhash", 8)) {
837 s.virtstyle=VIRT_CIDR;
838 if(strlen(virtstyle)<10) {
839 g_set_error(e, errdomain, CFILE_VALUE_INVALID, "Invalid value %s for parameter virtstyle in group %s: missing length", virtstyle, groups[i]);
840 g_array_free(retval, TRUE);
841 g_key_file_free(cfile);
844 s.cidrlen=strtol(virtstyle+8, NULL, 0);
846 g_set_error(e, errdomain, CFILE_VALUE_INVALID, "Invalid value %s for parameter virtstyle in group %s", virtstyle, groups[i]);
847 g_array_free(retval, TRUE);
848 g_key_file_free(cfile);
851 if(s.port && !do_oldstyle) {
852 g_warning("A port was specified, but oldstyle exports were not requested. This may not do what you expect.");
853 g_warning("Please read 'man 5 nbd-server' and search for oldstyle for more info");
856 s.virtstyle=VIRT_IPLIT;
858 /* Don't need to free this, it's not our string */
860 /* Don't append values for the [generic] group */
862 s.socket_family = AF_UNSPEC;
863 s.servename = groups[i];
865 append_serve(&s, retval);
872 if(s.flags & F_SDP) {
873 g_set_error(e, errdomain, CFILE_VALUE_UNSUPPORTED, "This nbd-server was built without support for SDP, yet group %s uses it", groups[i]);
874 g_array_free(retval, TRUE);
875 g_key_file_free(cfile);
881 g_set_error(e, errdomain, CFILE_NO_EXPORTS, "The config file does not specify any exports");
883 g_key_file_free(cfile);
888 * Signal handler for SIGCHLD
889 * @param s the signal we're handling (must be SIGCHLD, or something
892 void sigchld_handler(int s) {
897 while((pid=waitpid(-1, &status, WNOHANG)) > 0) {
898 if(WIFEXITED(status)) {
899 msg3(LOG_INFO, "Child exited with %d", WEXITSTATUS(status));
901 i=g_hash_table_lookup(children, &pid);
903 msg3(LOG_INFO, "SIGCHLD received for an unknown child with PID %ld", (long)pid);
905 DEBUG2("Removing %d from the list of children", pid);
906 g_hash_table_remove(children, &pid);
912 * Kill a child. Called from sigterm_handler::g_hash_table_foreach.
915 * @param value the value corresponding to the above key
916 * @param user_data a pointer which we always set to 1, so that we know what
919 void killchild(gpointer key, gpointer value, gpointer user_data) {
921 int *parent=user_data;
928 * Handle SIGTERM and dispatch it to our children
929 * @param s the signal we're handling (must be SIGTERM, or something
930 * is severely wrong).
932 void sigterm_handler(int s) {
935 g_hash_table_foreach(children, killchild, &parent);
945 * Detect the size of a file.
947 * @param fhandle An open filedescriptor
948 * @return the size of the file, or OFFT_MAX if detection was
951 off_t size_autodetect(int fhandle) {
954 struct stat stat_buf;
957 #ifdef HAVE_SYS_MOUNT_H
958 #ifdef HAVE_SYS_IOCTL_H
960 DEBUG("looking for export size with ioctl BLKGETSIZE64\n");
961 if (!ioctl(fhandle, BLKGETSIZE64, &bytes) && bytes) {
964 #endif /* BLKGETSIZE64 */
965 #endif /* HAVE_SYS_IOCTL_H */
966 #endif /* HAVE_SYS_MOUNT_H */
968 DEBUG("looking for fhandle size with fstat\n");
969 stat_buf.st_size = 0;
970 error = fstat(fhandle, &stat_buf);
972 if(stat_buf.st_size > 0)
973 return (off_t)stat_buf.st_size;
975 err("fstat failed: %m");
978 DEBUG("looking for fhandle size with lseek SEEK_END\n");
979 es = lseek(fhandle, (off_t)0, SEEK_END);
980 if (es > ((off_t)0)) {
983 DEBUG2("lseek failed: %d", errno==EBADF?1:(errno==ESPIPE?2:(errno==EINVAL?3:4)));
986 err("Could not find size of exported block device: %m");
991 * Get the file handle and offset, given an export offset.
993 * @param export An array of export files
994 * @param a The offset to get corresponding file/offset for
995 * @param fhandle [out] File descriptor
996 * @param foffset [out] Offset into fhandle
997 * @param maxbytes [out] Tells how many bytes can be read/written
998 * from fhandle starting at foffset (0 if there is no limit)
999 * @return 0 on success, -1 on failure
1001 int get_filepos(GArray* export, off_t a, int* fhandle, off_t* foffset, size_t* maxbytes ) {
1002 /* Negative offset not allowed */
1006 /* Binary search for last file with starting offset <= a */
1009 int end = export->len - 1;
1010 while( start <= end ) {
1011 int mid = (start + end) / 2;
1012 fi = g_array_index(export, FILE_INFO, mid);
1013 if( fi.startoff < a ) {
1015 } else if( fi.startoff > a ) {
1023 /* end should never go negative, since first startoff is 0 and a >= 0 */
1026 fi = g_array_index(export, FILE_INFO, end);
1027 *fhandle = fi.fhandle;
1028 *foffset = a - fi.startoff;
1030 if( end+1 < export->len ) {
1031 FILE_INFO fi_next = g_array_index(export, FILE_INFO, end+1);
1032 *maxbytes = fi_next.startoff - a;
1039 * seek to a position in a file, with error handling.
1040 * @param handle a filedescriptor
1041 * @param a position to seek to
1042 * @todo get rid of this; lastpoint is a global variable right now, but it
1043 * shouldn't be. If we pass it on as a parameter, that makes things a *lot*
1046 void myseek(int handle,off_t a) {
1047 if (lseek(handle, a, SEEK_SET) < 0) {
1048 err("Can not seek locally!\n");
1053 * Write an amount of bytes at a given offset to the right file. This
1054 * abstracts the write-side of the multiple file option.
1056 * @param a The offset where the write should start
1057 * @param buf The buffer to write from
1058 * @param len The length of buf
1059 * @param client The client we're serving for
1060 * @return The number of bytes actually written, or -1 in case of an error
1062 ssize_t rawexpwrite(off_t a, char *buf, size_t len, CLIENT *client) {
1068 if(get_filepos(client->export, a, &fhandle, &foffset, &maxbytes))
1070 if(maxbytes && len > maxbytes)
1073 DEBUG4("(WRITE to fd %d offset %llu len %u), ", fhandle, foffset, len);
1075 myseek(fhandle, foffset);
1076 retval = write(fhandle, buf, len);
1077 if(client->server->flags & F_SYNC) {
1084 * Call rawexpwrite repeatedly until all data has been written.
1085 * @return 0 on success, nonzero on failure
1087 int rawexpwrite_fully(off_t a, char *buf, size_t len, CLIENT *client) {
1090 while(len > 0 && (ret=rawexpwrite(a, buf, len, client)) > 0 ) {
1095 return (ret < 0 || len != 0);
1099 * Read an amount of bytes at a given offset from the right file. This
1100 * abstracts the read-side of the multiple files option.
1102 * @param a The offset where the read should start
1103 * @param buf A buffer to read into
1104 * @param len The size of buf
1105 * @param client The client we're serving for
1106 * @return The number of bytes actually read, or -1 in case of an
1109 ssize_t rawexpread(off_t a, char *buf, size_t len, CLIENT *client) {
1114 if(get_filepos(client->export, a, &fhandle, &foffset, &maxbytes))
1116 if(maxbytes && len > maxbytes)
1119 DEBUG4("(READ from fd %d offset %llu len %u), ", fhandle, foffset, len);
1121 myseek(fhandle, foffset);
1122 return read(fhandle, buf, len);
1126 * Call rawexpread repeatedly until all data has been read.
1127 * @return 0 on success, nonzero on failure
1129 int rawexpread_fully(off_t a, char *buf, size_t len, CLIENT *client) {
1132 while(len > 0 && (ret=rawexpread(a, buf, len, client)) > 0 ) {
1137 return (ret < 0 || len != 0);
1141 * Read an amount of bytes at a given offset from the right file. This
1142 * abstracts the read-side of the copyonwrite stuff, and calls
1143 * rawexpread() with the right parameters to do the actual work.
1144 * @param a The offset where the read should start
1145 * @param buf A buffer to read into
1146 * @param len The size of buf
1147 * @param client The client we're going to read for
1148 * @return 0 on success, nonzero on failure
1150 int expread(off_t a, char *buf, size_t len, CLIENT *client) {
1151 off_t rdlen, offset;
1152 off_t mapcnt, mapl, maph, pagestart;
1154 if (!(client->server->flags & F_COPYONWRITE))
1155 return(rawexpread_fully(a, buf, len, client));
1156 DEBUG3("Asked to read %d bytes at %llu.\n", len, (unsigned long long)a);
1158 mapl=a/DIFFPAGESIZE; maph=(a+len-1)/DIFFPAGESIZE;
1160 for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
1161 pagestart=mapcnt*DIFFPAGESIZE;
1163 rdlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
1164 len : (size_t)DIFFPAGESIZE-offset;
1165 if (client->difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
1166 DEBUG3("Page %llu is at %lu\n", (unsigned long long)mapcnt,
1167 (unsigned long)(client->difmap[mapcnt]));
1168 myseek(client->difffile, client->difmap[mapcnt]*DIFFPAGESIZE+offset);
1169 if (read(client->difffile, buf, rdlen) != rdlen) return -1;
1170 } else { /* the block is not there */
1171 DEBUG2("Page %llu is not here, we read the original one\n",
1172 (unsigned long long)mapcnt);
1173 if(rawexpread_fully(a, buf, rdlen, client)) return -1;
1175 len-=rdlen; a+=rdlen; buf+=rdlen;
1181 * Write an amount of bytes at a given offset to the right file. This
1182 * abstracts the write-side of the copyonwrite option, and calls
1183 * rawexpwrite() with the right parameters to do the actual work.
1185 * @param a The offset where the write should start
1186 * @param buf The buffer to write from
1187 * @param len The length of buf
1188 * @param client The client we're going to write for.
1189 * @return 0 on success, nonzero on failure
1191 int expwrite(off_t a, char *buf, size_t len, CLIENT *client) {
1192 char pagebuf[DIFFPAGESIZE];
1193 off_t mapcnt,mapl,maph;
1198 if (!(client->server->flags & F_COPYONWRITE))
1199 return(rawexpwrite_fully(a, buf, len, client));
1200 DEBUG3("Asked to write %d bytes at %llu.\n", len, (unsigned long long)a);
1202 mapl=a/DIFFPAGESIZE ; maph=(a+len-1)/DIFFPAGESIZE ;
1204 for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
1205 pagestart=mapcnt*DIFFPAGESIZE ;
1206 offset=a-pagestart ;
1207 wrlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
1208 len : (size_t)DIFFPAGESIZE-offset;
1210 if (client->difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
1211 DEBUG3("Page %llu is at %lu\n", (unsigned long long)mapcnt,
1212 (unsigned long)(client->difmap[mapcnt])) ;
1213 myseek(client->difffile,
1214 client->difmap[mapcnt]*DIFFPAGESIZE+offset);
1215 if (write(client->difffile, buf, wrlen) != wrlen) return -1 ;
1216 } else { /* the block is not there */
1217 myseek(client->difffile,client->difffilelen*DIFFPAGESIZE) ;
1218 client->difmap[mapcnt]=(client->server->flags&F_SPARSE)?mapcnt:client->difffilelen++;
1219 DEBUG3("Page %llu is not here, we put it at %lu\n",
1220 (unsigned long long)mapcnt,
1221 (unsigned long)(client->difmap[mapcnt]));
1222 rdlen=DIFFPAGESIZE ;
1223 if (rawexpread_fully(pagestart, pagebuf, rdlen, client))
1225 memcpy(pagebuf+offset,buf,wrlen) ;
1226 if (write(client->difffile, pagebuf, DIFFPAGESIZE) !=
1230 len-=wrlen ; a+=wrlen ; buf+=wrlen ;
1236 * Do the initial negotiation.
1238 * @param client The client we're negotiating with.
1240 CLIENT* negotiate(int net, CLIENT *client, GArray* servers) {
1243 uint32_t flags = NBD_FLAG_HAS_FLAGS;
1244 uint16_t smallflags = 0;
1247 memset(zeros, '\0', sizeof(zeros));
1248 if(!client || !client->modern) {
1250 if (write(net, INIT_PASSWD, 8) < 0) {
1251 err_nonfatal("Negotiation failed: %m");
1255 if(!client || client->modern) {
1257 magic = htonll(opts_magic);
1260 magic = htonll(cliserv_magic);
1262 if (write(net, &magic, sizeof(magic)) < 0) {
1263 err_nonfatal("Negotiation failed: %m");
1277 err("programmer error");
1278 if (write(net, &smallflags, sizeof(uint16_t)) < 0)
1279 err("Negotiation failed: %m");
1280 if (read(net, &reserved, sizeof(reserved)) < 0)
1281 err("Negotiation failed: %m");
1282 if (read(net, &magic, sizeof(magic)) < 0)
1283 err("Negotiation failed: %m");
1284 magic = ntohll(magic);
1285 if(magic != opts_magic) {
1289 if (read(net, &opt, sizeof(opt)) < 0)
1290 err("Negotiation failed: %m");
1292 if(opt != NBD_OPT_EXPORT_NAME) {
1296 if (read(net, &namelen, sizeof(namelen)) < 0)
1297 err("Negotiation failed: %m");
1298 namelen = ntohl(namelen);
1299 name = malloc(namelen+1);
1301 if (read(net, name, namelen) < 0)
1302 err("Negotiation failed: %m");
1303 for(i=0; i<servers->len; i++) {
1304 SERVER* serve = &(g_array_index(servers, SERVER, i));
1305 if(!strcmp(serve->servename, name)) {
1306 CLIENT* client = g_new0(CLIENT, 1);
1307 client->server = serve;
1308 client->exportsize = OFFT_MAX;
1310 client->modern = TRUE;
1317 size_host = htonll((u64)(client->exportsize));
1318 if (write(net, &size_host, 8) < 0)
1319 err("Negotiation failed: %m");
1320 if (client->server->flags & F_READONLY)
1321 flags |= NBD_FLAG_READ_ONLY;
1322 if (!client->modern) {
1324 flags = htonl(flags);
1325 if (write(client->net, &flags, 4) < 0)
1326 err("Negotiation failed: %m");
1329 smallflags = (uint16_t)(flags & ~((uint16_t)0));
1330 smallflags = htons(smallflags);
1331 if (write(client->net, &smallflags, sizeof(smallflags)) < 0) {
1332 err("Negotiation failed: %m");
1336 if (write(client->net, zeros, 124) < 0)
1337 err("Negotiation failed: %m");
1341 /** sending macro. */
1342 #define SEND(net,reply) writeit( net, &reply, sizeof( reply ));
1344 #define ERROR(client,reply,errcode) { reply.error = htonl(errcode); SEND(client->net,reply); reply.error = 0; }
1346 * Serve a file to a single client.
1348 * @todo This beast needs to be split up in many tiny little manageable
1349 * pieces. Preferably with a chainsaw.
1351 * @param client The client we're going to serve to.
1352 * @return when the client disconnects
1354 int mainloop(CLIENT *client) {
1355 struct nbd_request request;
1356 struct nbd_reply reply;
1357 gboolean go_on=TRUE;
1361 negotiate(client->net, client, NULL);
1362 DEBUG("Entering request loop!\n");
1363 reply.magic = htonl(NBD_REPLY_MAGIC);
1375 readit(client->net, &request, sizeof(request));
1376 request.from = ntohll(request.from);
1377 request.type = ntohl(request.type);
1379 if (request.type==NBD_CMD_DISC) {
1380 msg2(LOG_INFO, "Disconnect request received.");
1381 if (client->server->flags & F_COPYONWRITE) {
1382 if (client->difmap) g_free(client->difmap) ;
1383 close(client->difffile);
1384 unlink(client->difffilename);
1385 free(client->difffilename);
1391 len = ntohl(request.len);
1393 if (request.magic != htonl(NBD_REQUEST_MAGIC))
1394 err("Not enough magic.");
1395 if (len > BUFSIZE - sizeof(struct nbd_reply)) {
1396 currlen = BUFSIZE - sizeof(struct nbd_reply);
1397 msg2(LOG_INFO, "oversized request (this is not a problem)");
1402 printf("%s from %llu (%llu) len %d, ", request.type ? "WRITE" :
1403 "READ", (unsigned long long)request.from,
1404 (unsigned long long)request.from / 512, len);
1406 memcpy(reply.handle, request.handle, sizeof(reply.handle));
1407 if ((request.from + len) > (OFFT_MAX)) {
1408 DEBUG("[Number too large!]");
1409 ERROR(client, reply, EINVAL);
1413 if (((ssize_t)((off_t)request.from + len) > client->exportsize)) {
1415 ERROR(client, reply, EINVAL);
1419 if (request.type==NBD_CMD_WRITE) {
1420 DEBUG("wr: net->buf, ");
1422 readit(client->net, buf, currlen);
1423 DEBUG("buf->exp, ");
1424 if ((client->server->flags & F_READONLY) ||
1425 (client->server->flags & F_AUTOREADONLY)) {
1426 DEBUG("[WRITE to READONLY!]");
1427 ERROR(client, reply, EPERM);
1430 if (expwrite(request.from, buf, len, client)) {
1431 DEBUG("Write failed: %m" );
1432 ERROR(client, reply, errno);
1435 SEND(client->net, reply);
1438 currlen = (len < BUFSIZE) ? len : BUFSIZE;
1444 DEBUG("exp->buf, ");
1445 memcpy(buf, &reply, sizeof(struct nbd_reply));
1446 p = buf + sizeof(struct nbd_reply);
1447 writelen = currlen + sizeof(struct nbd_reply);
1449 if (expread(request.from, p, currlen, client)) {
1450 DEBUG("Read failed: %m");
1451 ERROR(client, reply, errno);
1455 DEBUG("buf->net, ");
1456 writeit(client->net, buf, writelen);
1458 currlen = (len < BUFSIZE) ? len : BUFSIZE;
1468 * Set up client export array, which is an array of FILE_INFO.
1469 * Also, split a single exportfile into multiple ones, if that was asked.
1470 * @param client information on the client which we want to setup export for
1472 void setupexport(CLIENT* client) {
1474 off_t laststartoff = 0, lastsize = 0;
1475 int multifile = (client->server->flags & F_MULTIFILE);
1477 client->export = g_array_new(TRUE, TRUE, sizeof(FILE_INFO));
1479 /* If multi-file, open as many files as we can.
1480 * If not, open exactly one file.
1481 * Calculate file sizes as we go to get total size. */
1485 gchar* error_string;
1486 mode_t mode = (client->server->flags & F_READONLY) ? O_RDONLY : O_RDWR;
1489 tmpname=g_strdup_printf("%s.%d", client->exportname, i);
1491 tmpname=g_strdup(client->exportname);
1493 DEBUG2( "Opening %s\n", tmpname );
1494 fi.fhandle = open(tmpname, mode);
1495 if(fi.fhandle == -1 && mode == O_RDWR) {
1496 /* Try again because maybe media was read-only */
1497 fi.fhandle = open(tmpname, O_RDONLY);
1498 if(fi.fhandle != -1) {
1499 /* Opening the base file in copyonwrite mode is
1501 if(!(client->server->flags & F_COPYONWRITE)) {
1502 client->server->flags |= F_AUTOREADONLY;
1503 client->server->flags |= F_READONLY;
1507 if(fi.fhandle == -1) {
1508 if(multifile && i>0)
1510 error_string=g_strdup_printf(
1511 "Could not open exported file %s: %%m",
1515 fi.startoff = laststartoff + lastsize;
1516 g_array_append_val(client->export, fi);
1519 /* Starting offset and size of this file will be used to
1520 * calculate starting offset of next file */
1521 laststartoff = fi.startoff;
1522 lastsize = size_autodetect(fi.fhandle);
1528 /* Set export size to total calculated size */
1529 client->exportsize = laststartoff + lastsize;
1531 /* Export size may be overridden */
1532 if(client->server->expected_size) {
1533 /* desired size must be <= total calculated size */
1534 if(client->server->expected_size > client->exportsize) {
1535 err("Size of exported file is too big\n");
1538 client->exportsize = client->server->expected_size;
1541 msg3(LOG_INFO, "Size of exported file/device is %llu", (unsigned long long)client->exportsize);
1543 msg3(LOG_INFO, "Total number of files: %d", i);
1547 int copyonwrite_prepare(CLIENT* client) {
1549 if ((client->difffilename = malloc(1024))==NULL)
1550 err("Failed to allocate string for diff file name");
1551 snprintf(client->difffilename, 1024, "%s-%s-%d.diff",client->exportname,client->clientname,
1553 client->difffilename[1023]='\0';
1554 msg3(LOG_INFO,"About to create map and diff file %s",client->difffilename) ;
1555 client->difffile=open(client->difffilename,O_RDWR | O_CREAT | O_TRUNC,0600) ;
1556 if (client->difffile<0) err("Could not create diff file (%m)") ;
1557 if ((client->difmap=calloc(client->exportsize/DIFFPAGESIZE,sizeof(u32)))==NULL)
1558 err("Could not allocate memory") ;
1559 for (i=0;i<client->exportsize/DIFFPAGESIZE;i++) client->difmap[i]=(u32)-1 ;
1565 * Run a command. This is used for the ``prerun'' and ``postrun'' config file
1568 * @param command the command to be ran. Read from the config file
1569 * @param file the file name we're about to export
1571 int do_run(gchar* command, gchar* file) {
1575 if(command && *command) {
1576 cmd = g_strdup_printf(command, file);
1584 * Serve a connection.
1586 * @todo allow for multithreading, perhaps use libevent. Not just yet, though;
1587 * follow the road map.
1589 * @param client a connected client
1591 void serveconnection(CLIENT *client) {
1592 if(do_run(client->server->prerun, client->exportname)) {
1595 setupexport(client);
1597 if (client->server->flags & F_COPYONWRITE) {
1598 copyonwrite_prepare(client);
1601 setmysockopt(client->net);
1604 do_run(client->server->postrun, client->exportname);
1608 * Find the name of the file we have to serve. This will use g_strdup_printf
1609 * to put the IP address of the client inside a filename containing
1610 * "%s" (in the form as specified by the "virtstyle" option). That name
1611 * is then written to client->exportname.
1613 * @param net A socket connected to an nbd client
1614 * @param client information about the client. The IP address in human-readable
1615 * format will be written to a new char* buffer, the address of which will be
1616 * stored in client->clientname.
1618 void set_peername(int net, CLIENT *client) {
1619 struct sockaddr_storage addrin;
1620 struct sockaddr_storage netaddr;
1621 struct sockaddr_in *netaddr4 = NULL;
1622 struct sockaddr_in6 *netaddr6 = NULL;
1623 size_t addrinlen = sizeof( addrin );
1624 struct addrinfo hints;
1625 struct addrinfo *ai = NULL;
1626 char peername[NI_MAXHOST];
1627 char netname[NI_MAXHOST];
1633 if (getpeername(net, (struct sockaddr *) &addrin, (socklen_t *)&addrinlen) < 0)
1634 err("getsockname failed: %m");
1636 getnameinfo((struct sockaddr *)&addrin, (socklen_t)addrinlen,
1637 peername, sizeof (peername), NULL, 0, NI_NUMERICHOST);
1639 memset(&hints, '\0', sizeof (hints));
1640 hints.ai_flags = AI_ADDRCONFIG;
1641 e = getaddrinfo(peername, NULL, &hints, &ai);
1644 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
1649 switch(client->server->virtstyle) {
1651 client->exportname=g_strdup(client->server->exportname);
1654 for(i=0;i<strlen(peername);i++) {
1655 if(peername[i]=='.') {
1660 client->exportname=g_strdup_printf(client->server->exportname, peername);
1663 memcpy(&netaddr, &addrin, addrinlen);
1664 if(ai->ai_family == AF_INET) {
1665 netaddr4 = (struct sockaddr_in *)&netaddr;
1666 (netaddr4->sin_addr).s_addr>>=32-(client->server->cidrlen);
1667 (netaddr4->sin_addr).s_addr<<=32-(client->server->cidrlen);
1669 getnameinfo((struct sockaddr *) netaddr4, (socklen_t) addrinlen,
1670 netname, sizeof (netname), NULL, 0, NI_NUMERICHOST);
1671 tmp=g_strdup_printf("%s/%s", netname, peername);
1672 }else if(ai->ai_family == AF_INET6) {
1673 netaddr6 = (struct sockaddr_in6 *)&netaddr;
1675 shift = 128-(client->server->cidrlen);
1677 while(shift >= 32) {
1678 ((netaddr6->sin6_addr).s6_addr32[i])=0;
1682 (netaddr6->sin6_addr).s6_addr32[i]>>=shift;
1683 (netaddr6->sin6_addr).s6_addr32[i]<<=shift;
1685 getnameinfo((struct sockaddr *)netaddr6, (socklen_t)addrinlen,
1686 netname, sizeof(netname), NULL, 0, NI_NUMERICHOST);
1687 tmp=g_strdup_printf("%s/%s", netname, peername);
1691 client->exportname=g_strdup_printf(client->server->exportname, tmp);
1697 msg4(LOG_INFO, "connect from %s, assigned file is %s",
1698 peername, client->exportname);
1699 client->clientname=g_strdup(peername);
1704 * @param data a pointer to pid_t which should be freed
1706 void destroy_pid_t(gpointer data) {
1711 * Loop through the available servers, and serve them. Never returns.
1713 int serveloop(GArray* servers) {
1714 struct sockaddr_storage addrin;
1715 socklen_t addrinlen=sizeof(addrin);
1723 * Set up the master fd_set. The set of descriptors we need
1724 * to select() for never changes anyway and it buys us a *lot*
1725 * of time to only build this once. However, if we ever choose
1726 * to not fork() for clients anymore, we may have to revisit
1731 for(i=0;i<servers->len;i++) {
1732 if((sock=(g_array_index(servers, SERVER, i)).socket)) {
1733 FD_SET(sock, &mset);
1734 max=sock>max?sock:max;
1738 FD_SET(modernsock, &mset);
1739 max=modernsock>max?modernsock:max;
1742 CLIENT *client = NULL;
1745 memcpy(&rset, &mset, sizeof(fd_set));
1746 if(select(max+1, &rset, NULL, NULL, NULL)>0) {
1751 if(FD_ISSET(modernsock, &rset)) {
1752 if((net=accept(modernsock, (struct sockaddr *) &addrin, &addrinlen)) < 0)
1754 client = negotiate(net, NULL, servers);
1756 err_nonfatal("negotiation failed");
1761 for(i=0;i<servers->len && !net;i++) {
1762 serve=&(g_array_index(servers, SERVER, i));
1763 if(FD_ISSET(serve->socket, &rset)) {
1764 if ((net=accept(serve->socket, (struct sockaddr *) &addrin, &addrinlen)) < 0)
1771 if(serve->max_connections > 0 &&
1772 g_hash_table_size(children) >= serve->max_connections) {
1773 msg2(LOG_INFO, "Max connections reached");
1777 if((sock_flags = fcntl(net, F_GETFL, 0))==-1) {
1778 err("fcntl F_GETFL");
1780 if(fcntl(net, F_SETFL, sock_flags &~O_NONBLOCK)==-1) {
1781 err("fcntl F_SETFL ~O_NONBLOCK");
1784 client = g_new0(CLIENT, 1);
1785 client->server=serve;
1786 client->exportsize=OFFT_MAX;
1789 set_peername(net, client);
1790 if (!authorized_client(client)) {
1791 msg2(LOG_INFO,"Unauthorized client") ;
1795 msg2(LOG_INFO,"Authorized client") ;
1796 pid=g_malloc(sizeof(pid_t));
1798 if ((*pid=fork())<0) {
1799 msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ;
1803 if (*pid>0) { /* parent */
1805 g_hash_table_insert(children, pid, pid);
1809 g_hash_table_destroy(children);
1810 for(i=0;i<servers->len;i++) {
1811 serve=&g_array_index(servers, SERVER, i);
1812 close(serve->socket);
1814 /* FALSE does not free the
1815 actual data. This is required,
1816 because the client has a
1817 direct reference into that
1818 data, and otherwise we get a
1820 g_array_free(servers, FALSE);
1822 msg2(LOG_INFO,"Starting to serve");
1823 serveconnection(client);
1830 void dosockopts(int socket) {
1838 /* lose the pesky "Address already in use" error message */
1839 if (setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
1840 err("setsockopt SO_REUSEADDR");
1842 if (setsockopt(socket,SOL_SOCKET,SO_KEEPALIVE,&yes,sizeof(int)) == -1) {
1843 err("setsockopt SO_KEEPALIVE");
1846 /* make the listening socket non-blocking */
1847 if ((sock_flags = fcntl(socket, F_GETFL, 0)) == -1) {
1848 err("fcntl F_GETFL");
1850 if (fcntl(socket, F_SETFL, sock_flags | O_NONBLOCK) == -1) {
1851 err("fcntl F_SETFL O_NONBLOCK");
1856 * Connect a server's socket.
1858 * @param serve the server we want to connect.
1860 int setup_serve(SERVER *serve) {
1861 struct addrinfo hints;
1862 struct addrinfo *ai = NULL;
1867 return serve->servename ? 1 : 0;
1869 memset(&hints,'\0',sizeof(hints));
1870 hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG | AI_NUMERICSERV;
1871 hints.ai_socktype = SOCK_STREAM;
1872 hints.ai_family = serve->socket_family;
1874 port = g_strdup_printf ("%d", serve->port);
1878 e = getaddrinfo(serve->listenaddr,port,&hints,&ai);
1883 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
1889 if(serve->socket_family == AF_UNSPEC)
1890 serve->socket_family = ai->ai_family;
1893 if ((serve->flags) && F_SDP) {
1894 if (ai->ai_family == AF_INET)
1895 ai->ai_family = AF_INET_SDP;
1896 else (ai->ai_family == AF_INET6)
1897 ai->ai_family = AF_INET6_SDP;
1900 if ((serve->socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0)
1903 dosockopts(serve->socket);
1905 DEBUG("Waiting for connections... bind, ");
1906 e = bind(serve->socket, ai->ai_addr, ai->ai_addrlen);
1907 if (e != 0 && errno != EADDRINUSE)
1910 if (listen(serve->socket, 1) < 0)
1914 if(serve->servename) {
1921 void open_modern(void) {
1922 struct addrinfo hints;
1923 struct addrinfo* ai = NULL;
1927 memset(&hints, '\0', sizeof(hints));
1928 hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
1929 hints.ai_socktype = SOCK_STREAM;
1930 hints.ai_family = AF_UNSPEC;
1931 hints.ai_protocol = IPPROTO_TCP;
1932 e = getaddrinfo(modern_listen, NBD_DEFAULT_PORT, &hints, &ai);
1934 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
1937 if((modernsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))<0) {
1941 dosockopts(modernsock);
1943 if(bind(modernsock, ai->ai_addr, ai->ai_addrlen)) {
1946 if(listen(modernsock, 10) <0) {
1954 * Connect our servers.
1956 void setup_servers(GArray* servers) {
1958 struct sigaction sa;
1961 for(i=0;i<servers->len;i++) {
1962 want_modern |= setup_serve(&(g_array_index(servers, SERVER, i)));
1967 children=g_hash_table_new_full(g_int_hash, g_int_equal, NULL, destroy_pid_t);
1969 sa.sa_handler = sigchld_handler;
1970 sigemptyset(&sa.sa_mask);
1971 sa.sa_flags = SA_RESTART;
1972 if(sigaction(SIGCHLD, &sa, NULL) == -1)
1973 err("sigaction: %m");
1974 sa.sa_handler = sigterm_handler;
1975 sigemptyset(&sa.sa_mask);
1976 sa.sa_flags = SA_RESTART;
1977 if(sigaction(SIGTERM, &sa, NULL) == -1)
1978 err("sigaction: %m");
1982 * Go daemon (unless we specified at compile time that we didn't want this)
1983 * @param serve the first server of our configuration. If its port is zero,
1984 * then do not daemonize, because we're doing inetd then. This parameter
1985 * is only used to create a PID file of the form
1986 * /var/run/nbd-server.<port>.pid; it's not modified in any way.
1988 #if !defined(NODAEMON) && !defined(NOFORK)
1989 void daemonize(SERVER* serve) {
1992 if(serve && !(serve->port)) {
1998 if(!*pidftemplate) {
2000 strncpy(pidftemplate, "/var/run/nbd-server.%d.pid", 255);
2002 strncpy(pidftemplate, "/var/run/nbd-server.pid", 255);
2005 snprintf(pidfname, 255, pidftemplate, serve ? serve->port : 0);
2006 pidf=fopen(pidfname, "w");
2008 fprintf(pidf,"%d\n", (int)getpid());
2012 fprintf(stderr, "Not fatal; continuing");
2016 #define daemonize(serve)
2017 #endif /* !defined(NODAEMON) && !defined(NOFORK) */
2020 * Everything beyond this point (in the file) is run in non-daemon mode.
2021 * The stuff above daemonize() isn't.
2024 void serve_err(SERVER* serve, const char* msg) G_GNUC_NORETURN;
2026 void serve_err(SERVER* serve, const char* msg) {
2027 g_message("Export of %s on port %d failed:", serve->exportname,
2033 * Set up user-ID and/or group-ID
2035 void dousers(void) {
2040 gr=getgrnam(rungroup);
2042 str = g_strdup_printf("Invalid group name: %s", rungroup);
2045 if(setgid(gr->gr_gid)<0) {
2046 err("Could not set GID: %m");
2050 pw=getpwnam(runuser);
2052 str = g_strdup_printf("Invalid user name: %s", runuser);
2055 if(setuid(pw->pw_uid)<0) {
2056 err("Could not set UID: %m");
2062 void glib_message_syslog_redirect(const gchar *log_domain,
2063 GLogLevelFlags log_level,
2064 const gchar *message,
2067 int level=LOG_DEBUG;
2071 case G_LOG_FLAG_FATAL:
2072 case G_LOG_LEVEL_CRITICAL:
2073 case G_LOG_LEVEL_ERROR:
2076 case G_LOG_LEVEL_WARNING:
2079 case G_LOG_LEVEL_MESSAGE:
2080 case G_LOG_LEVEL_INFO:
2083 case G_LOG_LEVEL_DEBUG:
2088 syslog(level, "%s", message);
2093 * Main entry point...
2095 int main(int argc, char *argv[]) {
2100 if (sizeof( struct nbd_request )!=28) {
2101 fprintf(stderr,"Bad size of structure. Alignment problems?\n");
2102 exit(EXIT_FAILURE) ;
2105 memset(pidftemplate, '\0', 256);
2108 config_file_pos = g_strdup(CFILE);
2109 serve=cmdline(argc, argv);
2110 servers = parse_cfile(config_file_pos, &err);
2113 serve->socket_family = AF_UNSPEC;
2115 append_serve(serve, servers);
2117 if (!(serve->port)) {
2120 /* You really should define ISSERVER if you're going to use
2121 * inetd mode, but if you don't, closing stdout and stderr
2122 * (which inetd had connected to the client socket) will let it
2126 open("/dev/null", O_WRONLY);
2127 open("/dev/null", O_WRONLY);
2128 g_log_set_default_handler( glib_message_syslog_redirect, NULL );
2130 client=g_malloc(sizeof(CLIENT));
2131 client->server=serve;
2133 client->exportsize=OFFT_MAX;
2134 set_peername(0,client);
2135 serveconnection(client);
2140 if(!servers || !servers->len) {
2141 if(err && !(err->domain == g_quark_from_string("parse_cfile")
2142 && err->code == CFILE_NOTFOUND)) {
2143 g_warning("Could not parse config file: %s",
2144 err ? err->message : "Unknown error");
2148 g_warning("Specifying an export on the command line is deprecated.");
2149 g_warning("Please use a configuration file instead.");
2152 if((!serve) && (!servers||!servers->len)) {
2153 g_message("No configured exports; quitting.");
2157 setup_servers(servers);