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) /**< 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);
1372 readit(client->net, &request, sizeof(request));
1373 request.from = ntohll(request.from);
1374 request.type = ntohl(request.type);
1376 if (request.type==NBD_CMD_DISC) {
1377 msg2(LOG_INFO, "Disconnect request received.");
1378 if (client->server->flags & F_COPYONWRITE) {
1379 if (client->difmap) g_free(client->difmap) ;
1380 close(client->difffile);
1381 unlink(client->difffilename);
1382 free(client->difffilename);
1388 len = ntohl(request.len);
1390 if (request.magic != htonl(NBD_REQUEST_MAGIC))
1391 err("Not enough magic.");
1392 if (len > BUFSIZE + sizeof(struct nbd_reply))
1393 err("Request too big!");
1395 printf("%s from %llu (%llu) len %d, ", request.type ? "WRITE" :
1396 "READ", (unsigned long long)request.from,
1397 (unsigned long long)request.from / 512, len);
1399 memcpy(reply.handle, request.handle, sizeof(reply.handle));
1400 if ((request.from + len) > (OFFT_MAX)) {
1401 DEBUG("[Number too large!]");
1402 ERROR(client, reply, EINVAL);
1406 if (((ssize_t)((off_t)request.from + len) > client->exportsize)) {
1408 ERROR(client, reply, EINVAL);
1412 if (request.type==NBD_CMD_WRITE) {
1413 DEBUG("wr: net->buf, ");
1414 readit(client->net, buf, len);
1415 DEBUG("buf->exp, ");
1416 if ((client->server->flags & F_READONLY) ||
1417 (client->server->flags & F_AUTOREADONLY)) {
1418 DEBUG("[WRITE to READONLY!]");
1419 ERROR(client, reply, EPERM);
1422 if (expwrite(request.from, buf, len, client)) {
1423 DEBUG("Write failed: %m" );
1424 ERROR(client, reply, errno);
1427 SEND(client->net, reply);
1433 DEBUG("exp->buf, ");
1434 if (expread(request.from, buf + sizeof(struct nbd_reply), len, client)) {
1435 DEBUG("Read failed: %m");
1436 ERROR(client, reply, errno);
1440 DEBUG("buf->net, ");
1441 memcpy(buf, &reply, sizeof(struct nbd_reply));
1442 writeit(client->net, buf, len + sizeof(struct nbd_reply));
1449 * Set up client export array, which is an array of FILE_INFO.
1450 * Also, split a single exportfile into multiple ones, if that was asked.
1451 * @param client information on the client which we want to setup export for
1453 void setupexport(CLIENT* client) {
1455 off_t laststartoff = 0, lastsize = 0;
1456 int multifile = (client->server->flags & F_MULTIFILE);
1458 client->export = g_array_new(TRUE, TRUE, sizeof(FILE_INFO));
1460 /* If multi-file, open as many files as we can.
1461 * If not, open exactly one file.
1462 * Calculate file sizes as we go to get total size. */
1466 gchar* error_string;
1467 mode_t mode = (client->server->flags & F_READONLY) ? O_RDONLY : O_RDWR;
1470 tmpname=g_strdup_printf("%s.%d", client->exportname, i);
1472 tmpname=g_strdup(client->exportname);
1474 DEBUG2( "Opening %s\n", tmpname );
1475 fi.fhandle = open(tmpname, mode);
1476 if(fi.fhandle == -1 && mode == O_RDWR) {
1477 /* Try again because maybe media was read-only */
1478 fi.fhandle = open(tmpname, O_RDONLY);
1479 if(fi.fhandle != -1) {
1480 /* Opening the base file in copyonwrite mode is
1482 if(!(client->server->flags & F_COPYONWRITE)) {
1483 client->server->flags |= F_AUTOREADONLY;
1484 client->server->flags |= F_READONLY;
1488 if(fi.fhandle == -1) {
1489 if(multifile && i>0)
1491 error_string=g_strdup_printf(
1492 "Could not open exported file %s: %%m",
1496 fi.startoff = laststartoff + lastsize;
1497 g_array_append_val(client->export, fi);
1500 /* Starting offset and size of this file will be used to
1501 * calculate starting offset of next file */
1502 laststartoff = fi.startoff;
1503 lastsize = size_autodetect(fi.fhandle);
1509 /* Set export size to total calculated size */
1510 client->exportsize = laststartoff + lastsize;
1512 /* Export size may be overridden */
1513 if(client->server->expected_size) {
1514 /* desired size must be <= total calculated size */
1515 if(client->server->expected_size > client->exportsize) {
1516 err("Size of exported file is too big\n");
1519 client->exportsize = client->server->expected_size;
1522 msg3(LOG_INFO, "Size of exported file/device is %llu", (unsigned long long)client->exportsize);
1524 msg3(LOG_INFO, "Total number of files: %d", i);
1528 int copyonwrite_prepare(CLIENT* client) {
1530 if ((client->difffilename = malloc(1024))==NULL)
1531 err("Failed to allocate string for diff file name");
1532 snprintf(client->difffilename, 1024, "%s-%s-%d.diff",client->exportname,client->clientname,
1534 client->difffilename[1023]='\0';
1535 msg3(LOG_INFO,"About to create map and diff file %s",client->difffilename) ;
1536 client->difffile=open(client->difffilename,O_RDWR | O_CREAT | O_TRUNC,0600) ;
1537 if (client->difffile<0) err("Could not create diff file (%m)") ;
1538 if ((client->difmap=calloc(client->exportsize/DIFFPAGESIZE,sizeof(u32)))==NULL)
1539 err("Could not allocate memory") ;
1540 for (i=0;i<client->exportsize/DIFFPAGESIZE;i++) client->difmap[i]=(u32)-1 ;
1546 * Run a command. This is used for the ``prerun'' and ``postrun'' config file
1549 * @param command the command to be ran. Read from the config file
1550 * @param file the file name we're about to export
1552 int do_run(gchar* command, gchar* file) {
1556 if(command && *command) {
1557 cmd = g_strdup_printf(command, file);
1565 * Serve a connection.
1567 * @todo allow for multithreading, perhaps use libevent. Not just yet, though;
1568 * follow the road map.
1570 * @param client a connected client
1572 void serveconnection(CLIENT *client) {
1573 if(do_run(client->server->prerun, client->exportname)) {
1576 setupexport(client);
1578 if (client->server->flags & F_COPYONWRITE) {
1579 copyonwrite_prepare(client);
1582 setmysockopt(client->net);
1585 do_run(client->server->postrun, client->exportname);
1589 * Find the name of the file we have to serve. This will use g_strdup_printf
1590 * to put the IP address of the client inside a filename containing
1591 * "%s" (in the form as specified by the "virtstyle" option). That name
1592 * is then written to client->exportname.
1594 * @param net A socket connected to an nbd client
1595 * @param client information about the client. The IP address in human-readable
1596 * format will be written to a new char* buffer, the address of which will be
1597 * stored in client->clientname.
1599 void set_peername(int net, CLIENT *client) {
1600 struct sockaddr_storage addrin;
1601 struct sockaddr_storage netaddr;
1602 struct sockaddr_in *netaddr4 = NULL;
1603 struct sockaddr_in6 *netaddr6 = NULL;
1604 size_t addrinlen = sizeof( addrin );
1605 struct addrinfo hints;
1606 struct addrinfo *ai = NULL;
1607 char peername[NI_MAXHOST];
1608 char netname[NI_MAXHOST];
1614 if (getpeername(net, (struct sockaddr *) &addrin, (socklen_t *)&addrinlen) < 0)
1615 err("getsockname failed: %m");
1617 getnameinfo((struct sockaddr *)&addrin, (socklen_t)addrinlen,
1618 peername, sizeof (peername), NULL, 0, NI_NUMERICHOST);
1620 memset(&hints, '\0', sizeof (hints));
1621 hints.ai_flags = AI_ADDRCONFIG;
1622 e = getaddrinfo(peername, NULL, &hints, &ai);
1625 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
1630 switch(client->server->virtstyle) {
1632 client->exportname=g_strdup(client->server->exportname);
1635 for(i=0;i<strlen(peername);i++) {
1636 if(peername[i]=='.') {
1641 client->exportname=g_strdup_printf(client->server->exportname, peername);
1644 memcpy(&netaddr, &addrin, addrinlen);
1645 if(ai->ai_family == AF_INET) {
1646 netaddr4 = (struct sockaddr_in *)&netaddr;
1647 (netaddr4->sin_addr).s_addr>>=32-(client->server->cidrlen);
1648 (netaddr4->sin_addr).s_addr<<=32-(client->server->cidrlen);
1650 getnameinfo((struct sockaddr *) netaddr4, (socklen_t) addrinlen,
1651 netname, sizeof (netname), NULL, 0, NI_NUMERICHOST);
1652 tmp=g_strdup_printf("%s/%s", netname, peername);
1653 }else if(ai->ai_family == AF_INET6) {
1654 netaddr6 = (struct sockaddr_in6 *)&netaddr;
1656 shift = 128-(client->server->cidrlen);
1658 while(shift >= 32) {
1659 ((netaddr6->sin6_addr).s6_addr32[i])=0;
1663 (netaddr6->sin6_addr).s6_addr32[i]>>=shift;
1664 (netaddr6->sin6_addr).s6_addr32[i]<<=shift;
1666 getnameinfo((struct sockaddr *)netaddr6, (socklen_t)addrinlen,
1667 netname, sizeof(netname), NULL, 0, NI_NUMERICHOST);
1668 tmp=g_strdup_printf("%s/%s", netname, peername);
1672 client->exportname=g_strdup_printf(client->server->exportname, tmp);
1678 msg4(LOG_INFO, "connect from %s, assigned file is %s",
1679 peername, client->exportname);
1680 client->clientname=g_strdup(peername);
1685 * @param data a pointer to pid_t which should be freed
1687 void destroy_pid_t(gpointer data) {
1692 * Loop through the available servers, and serve them. Never returns.
1694 int serveloop(GArray* servers) {
1695 struct sockaddr_storage addrin;
1696 socklen_t addrinlen=sizeof(addrin);
1704 * Set up the master fd_set. The set of descriptors we need
1705 * to select() for never changes anyway and it buys us a *lot*
1706 * of time to only build this once. However, if we ever choose
1707 * to not fork() for clients anymore, we may have to revisit
1712 for(i=0;i<servers->len;i++) {
1713 if((sock=(g_array_index(servers, SERVER, i)).socket)) {
1714 FD_SET(sock, &mset);
1715 max=sock>max?sock:max;
1719 FD_SET(modernsock, &mset);
1720 max=modernsock>max?modernsock:max;
1723 CLIENT *client = NULL;
1726 memcpy(&rset, &mset, sizeof(fd_set));
1727 if(select(max+1, &rset, NULL, NULL, NULL)>0) {
1732 if(FD_ISSET(modernsock, &rset)) {
1733 if((net=accept(modernsock, (struct sockaddr *) &addrin, &addrinlen)) < 0)
1735 client = negotiate(net, NULL, servers);
1737 err_nonfatal("negotiation failed");
1742 for(i=0;i<servers->len && !net;i++) {
1743 serve=&(g_array_index(servers, SERVER, i));
1744 if(FD_ISSET(serve->socket, &rset)) {
1745 if ((net=accept(serve->socket, (struct sockaddr *) &addrin, &addrinlen)) < 0)
1752 if(serve->max_connections > 0 &&
1753 g_hash_table_size(children) >= serve->max_connections) {
1754 msg2(LOG_INFO, "Max connections reached");
1758 if((sock_flags = fcntl(net, F_GETFL, 0))==-1) {
1759 err("fcntl F_GETFL");
1761 if(fcntl(net, F_SETFL, sock_flags &~O_NONBLOCK)==-1) {
1762 err("fcntl F_SETFL ~O_NONBLOCK");
1765 client = g_new0(CLIENT, 1);
1766 client->server=serve;
1767 client->exportsize=OFFT_MAX;
1770 set_peername(net, client);
1771 if (!authorized_client(client)) {
1772 msg2(LOG_INFO,"Unauthorized client") ;
1776 msg2(LOG_INFO,"Authorized client") ;
1777 pid=g_malloc(sizeof(pid_t));
1779 if ((*pid=fork())<0) {
1780 msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ;
1784 if (*pid>0) { /* parent */
1786 g_hash_table_insert(children, pid, pid);
1790 g_hash_table_destroy(children);
1791 for(i=0;i<servers->len;i++) {
1792 serve=&g_array_index(servers, SERVER, i);
1793 close(serve->socket);
1795 /* FALSE does not free the
1796 actual data. This is required,
1797 because the client has a
1798 direct reference into that
1799 data, and otherwise we get a
1801 g_array_free(servers, FALSE);
1803 msg2(LOG_INFO,"Starting to serve");
1804 serveconnection(client);
1811 void dosockopts(int socket) {
1819 /* lose the pesky "Address already in use" error message */
1820 if (setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
1821 err("setsockopt SO_REUSEADDR");
1823 if (setsockopt(socket,SOL_SOCKET,SO_KEEPALIVE,&yes,sizeof(int)) == -1) {
1824 err("setsockopt SO_KEEPALIVE");
1827 /* make the listening socket non-blocking */
1828 if ((sock_flags = fcntl(socket, F_GETFL, 0)) == -1) {
1829 err("fcntl F_GETFL");
1831 if (fcntl(socket, F_SETFL, sock_flags | O_NONBLOCK) == -1) {
1832 err("fcntl F_SETFL O_NONBLOCK");
1837 * Connect a server's socket.
1839 * @param serve the server we want to connect.
1841 int setup_serve(SERVER *serve) {
1842 struct addrinfo hints;
1843 struct addrinfo *ai = NULL;
1848 return serve->servename ? 1 : 0;
1850 memset(&hints,'\0',sizeof(hints));
1851 hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG | AI_NUMERICSERV;
1852 hints.ai_socktype = SOCK_STREAM;
1853 hints.ai_family = serve->socket_family;
1855 port = g_strdup_printf ("%d", serve->port);
1859 e = getaddrinfo(serve->listenaddr,port,&hints,&ai);
1864 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
1870 if(serve->socket_family == AF_UNSPEC)
1871 serve->socket_family = ai->ai_family;
1874 if ((serve->flags) && F_SDP) {
1875 if (ai->ai_family == AF_INET)
1876 ai->ai_family = AF_INET_SDP;
1877 else (ai->ai_family == AF_INET6)
1878 ai->ai_family = AF_INET6_SDP;
1881 if ((serve->socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0)
1884 dosockopts(serve->socket);
1886 DEBUG("Waiting for connections... bind, ");
1887 e = bind(serve->socket, ai->ai_addr, ai->ai_addrlen);
1888 if (e != 0 && errno != EADDRINUSE)
1891 if (listen(serve->socket, 1) < 0)
1895 if(serve->servename) {
1902 void open_modern(void) {
1903 struct addrinfo hints;
1904 struct addrinfo* ai = NULL;
1908 memset(&hints, '\0', sizeof(hints));
1909 hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
1910 hints.ai_socktype = SOCK_STREAM;
1911 hints.ai_family = AF_UNSPEC;
1912 hints.ai_protocol = IPPROTO_TCP;
1913 e = getaddrinfo(modern_listen, NBD_DEFAULT_PORT, &hints, &ai);
1915 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
1918 if((modernsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))<0) {
1922 dosockopts(modernsock);
1924 if(bind(modernsock, ai->ai_addr, ai->ai_addrlen)) {
1927 if(listen(modernsock, 10) <0) {
1935 * Connect our servers.
1937 void setup_servers(GArray* servers) {
1939 struct sigaction sa;
1942 for(i=0;i<servers->len;i++) {
1943 want_modern |= setup_serve(&(g_array_index(servers, SERVER, i)));
1948 children=g_hash_table_new_full(g_int_hash, g_int_equal, NULL, destroy_pid_t);
1950 sa.sa_handler = sigchld_handler;
1951 sigemptyset(&sa.sa_mask);
1952 sa.sa_flags = SA_RESTART;
1953 if(sigaction(SIGCHLD, &sa, NULL) == -1)
1954 err("sigaction: %m");
1955 sa.sa_handler = sigterm_handler;
1956 sigemptyset(&sa.sa_mask);
1957 sa.sa_flags = SA_RESTART;
1958 if(sigaction(SIGTERM, &sa, NULL) == -1)
1959 err("sigaction: %m");
1963 * Go daemon (unless we specified at compile time that we didn't want this)
1964 * @param serve the first server of our configuration. If its port is zero,
1965 * then do not daemonize, because we're doing inetd then. This parameter
1966 * is only used to create a PID file of the form
1967 * /var/run/nbd-server.<port>.pid; it's not modified in any way.
1969 #if !defined(NODAEMON) && !defined(NOFORK)
1970 void daemonize(SERVER* serve) {
1973 if(serve && !(serve->port)) {
1979 if(!*pidftemplate) {
1981 strncpy(pidftemplate, "/var/run/nbd-server.%d.pid", 255);
1983 strncpy(pidftemplate, "/var/run/nbd-server.pid", 255);
1986 snprintf(pidfname, 255, pidftemplate, serve ? serve->port : 0);
1987 pidf=fopen(pidfname, "w");
1989 fprintf(pidf,"%d\n", (int)getpid());
1993 fprintf(stderr, "Not fatal; continuing");
1997 #define daemonize(serve)
1998 #endif /* !defined(NODAEMON) && !defined(NOFORK) */
2001 * Everything beyond this point (in the file) is run in non-daemon mode.
2002 * The stuff above daemonize() isn't.
2005 void serve_err(SERVER* serve, const char* msg) G_GNUC_NORETURN;
2007 void serve_err(SERVER* serve, const char* msg) {
2008 g_message("Export of %s on port %d failed:", serve->exportname,
2014 * Set up user-ID and/or group-ID
2016 void dousers(void) {
2021 gr=getgrnam(rungroup);
2023 str = g_strdup_printf("Invalid group name: %s", rungroup);
2026 if(setgid(gr->gr_gid)<0) {
2027 err("Could not set GID: %m");
2031 pw=getpwnam(runuser);
2033 str = g_strdup_printf("Invalid user name: %s", runuser);
2036 if(setuid(pw->pw_uid)<0) {
2037 err("Could not set UID: %m");
2043 void glib_message_syslog_redirect(const gchar *log_domain,
2044 GLogLevelFlags log_level,
2045 const gchar *message,
2048 int level=LOG_DEBUG;
2052 case G_LOG_FLAG_FATAL:
2053 case G_LOG_LEVEL_CRITICAL:
2054 case G_LOG_LEVEL_ERROR:
2057 case G_LOG_LEVEL_WARNING:
2060 case G_LOG_LEVEL_MESSAGE:
2061 case G_LOG_LEVEL_INFO:
2064 case G_LOG_LEVEL_DEBUG:
2069 syslog(level, "%s", message);
2074 * Main entry point...
2076 int main(int argc, char *argv[]) {
2081 if (sizeof( struct nbd_request )!=28) {
2082 fprintf(stderr,"Bad size of structure. Alignment problems?\n");
2083 exit(EXIT_FAILURE) ;
2086 memset(pidftemplate, '\0', 256);
2089 config_file_pos = g_strdup(CFILE);
2090 serve=cmdline(argc, argv);
2091 servers = parse_cfile(config_file_pos, &err);
2094 serve->socket_family = AF_UNSPEC;
2096 append_serve(serve, servers);
2098 if (!(serve->port)) {
2101 /* You really should define ISSERVER if you're going to use
2102 * inetd mode, but if you don't, closing stdout and stderr
2103 * (which inetd had connected to the client socket) will let it
2107 open("/dev/null", O_WRONLY);
2108 open("/dev/null", O_WRONLY);
2109 g_log_set_default_handler( glib_message_syslog_redirect, NULL );
2111 client=g_malloc(sizeof(CLIENT));
2112 client->server=serve;
2114 client->exportsize=OFFT_MAX;
2115 set_peername(0,client);
2116 serveconnection(client);
2121 if(!servers || !servers->len) {
2122 if(err && !(err->domain == g_quark_from_string("parse_cfile")
2123 && err->code == CFILE_NOTFOUND)) {
2124 g_warning("Could not parse config file: %s",
2125 err ? err->message : "Unknown error");
2129 g_warning("Specifying an export on the command line is deprecated.");
2130 g_warning("Please use a configuration file instead.");
2133 if((!serve) && (!servers||!servers->len)) {
2134 g_message("No configured exports; quitting.");
2138 setup_servers(servers);