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 /* Whether we should avoid forking */
122 /** Logging macros, now nothing goes to syslog unless you say ISSERVER */
124 #define msg2(a,b) syslog(a,b)
125 #define msg3(a,b,c) syslog(a,b,c)
126 #define msg4(a,b,c,d) syslog(a,b,c,d)
128 #define msg2(a,b) g_message(b)
129 #define msg3(a,b,c) g_message(b,c)
130 #define msg4(a,b,c,d) g_message(b,c,d)
133 /* Debugging macros */
136 #define DEBUG( a ) printf( a )
137 #define DEBUG2( a,b ) printf( a,b )
138 #define DEBUG3( a,b,c ) printf( a,b,c )
139 #define DEBUG4( a,b,c,d ) printf( a,b,c,d )
142 #define DEBUG2( a,b )
143 #define DEBUG3( a,b,c )
144 #define DEBUG4( a,b,c,d )
146 #ifndef PACKAGE_VERSION
147 #define PACKAGE_VERSION ""
150 * The highest value a variable of type off_t can reach. This is a signed
151 * integer, so set all bits except for the leftmost one.
153 #define OFFT_MAX ~((off_t)1<<(sizeof(off_t)*8-1))
154 #define LINELEN 256 /**< Size of static buffer used to read the
155 authorization file (yuck) */
156 #define BUFSIZE ((1024*1024)+sizeof(struct nbd_reply)) /**< Size of buffer that can hold requests */
157 #define DIFFPAGESIZE 4096 /**< diff file uses those chunks */
158 #define F_READONLY 1 /**< flag to tell us a file is readonly */
159 #define F_MULTIFILE 2 /**< flag to tell us a file is exported using -m */
160 #define F_COPYONWRITE 4 /**< flag to tell us a file is exported using
162 #define F_AUTOREADONLY 8 /**< flag to tell us a file is set to autoreadonly */
163 #define F_SPARSE 16 /**< flag to tell us copyronwrite should use a sparse file */
164 #define F_SDP 32 /**< flag to tell us the export should be done using the Socket Direct Protocol for RDMA */
165 #define F_SYNC 64 /**< Whether to fsync() after a write */
166 GHashTable *children;
167 char pidfname[256]; /**< name of our PID file */
168 char pidftemplate[256]; /**< template to be used for the filename of the PID file */
169 char default_authname[] = SYSCONFDIR "/nbd-server/allow"; /**< default name of allow file */
171 int modernsock=0; /**< Socket for the modern handler. Not used
172 if a client was only specified on the
173 command line; only port used if
174 oldstyle is set to false (and then the
175 command-line client isn't used, gna gna) */
176 char* modern_listen; /**< listenaddr value for modernsock */
179 * Types of virtuatlization
182 VIRT_NONE=0, /**< No virtualization */
183 VIRT_IPLIT, /**< Literal IP address as part of the filename */
184 VIRT_IPHASH, /**< Replacing all dots in an ip address by a / before
185 doing the same as in IPLIT */
186 VIRT_CIDR, /**< Every subnet in its own directory */
190 * Variables associated with a server.
193 gchar* exportname; /**< (unprocessed) filename of the file we're exporting */
194 off_t expected_size; /**< size of the exported file as it was told to
195 us through configuration */
196 gchar* listenaddr; /**< The IP address we're listening on */
197 unsigned int port; /**< port we're exporting this file at */
198 char* authname; /**< filename of the authorization file */
199 int flags; /**< flags associated with this exported file */
200 int socket; /**< The socket of this server. */
201 int socket_family; /**< family of the socket */
202 VIRT_STYLE virtstyle;/**< The style of virtualization, if any */
203 uint8_t cidrlen; /**< The length of the mask when we use
204 CIDR-style virtualization */
205 gchar* prerun; /**< command to be ran after connecting a client,
206 but before starting to serve */
207 gchar* postrun; /**< command that will be ran after the client
209 gchar* servename; /**< name of the export as selected by nbd-client */
210 int max_connections; /**< maximum number of opened connections */
214 * Variables associated with a client socket.
217 int fhandle; /**< file descriptor */
218 off_t startoff; /**< starting offset of this file */
222 off_t exportsize; /**< size of the file we're exporting */
223 char *clientname; /**< peer */
224 char *exportname; /**< (processed) filename of the file we're exporting */
225 GArray *export; /**< array of FILE_INFO of exported files;
226 array size is always 1 unless we're
227 doing the multiple file option */
228 int net; /**< The actual client socket */
229 SERVER *server; /**< The server this client is getting data from */
230 char* difffilename; /**< filename of the copy-on-write file, if any */
231 int difffile; /**< filedescriptor of copyonwrite file. @todo
232 shouldn't this be an array too? (cfr export) Or
233 make -m and -c mutually exclusive */
234 u32 difffilelen; /**< number of pages in difffile */
235 u32 *difmap; /**< see comment on the global difmap for this one */
236 gboolean modern; /**< client was negotiated using modern negotiation protocol */
240 * Type of configuration file values
243 PARAM_INT, /**< This parameter is an integer */
244 PARAM_STRING, /**< This parameter is a string */
245 PARAM_BOOL, /**< This parameter is a boolean */
249 * Configuration file values
252 gchar *paramname; /**< Name of the parameter, as it appears in
254 gboolean required; /**< Whether this is a required (as opposed to
255 optional) parameter */
256 PARAM_TYPE ptype; /**< Type of the parameter. */
257 gpointer target; /**< Pointer to where the data of this
258 parameter should be written. If ptype is
259 PARAM_BOOL, the data is or'ed rather than
261 gint flagval; /**< Flag mask for this parameter in case ptype
266 * Check whether a client is allowed to connect. Works with an authorization
267 * file which contains one line per machine, no wildcards.
269 * @param opts The client who's trying to connect.
270 * @return 0 - authorization refused, 1 - OK
272 int authorized_client(CLIENT *opts) {
273 const char *ERRMSG="Invalid entry '%s' in authfile '%s', so, refusing all connections.";
278 struct in_addr client;
279 struct in_addr cltemp;
282 if ((f=fopen(opts->server->authname,"r"))==NULL) {
283 msg4(LOG_INFO,"Can't open authorization file %s (%s).",
284 opts->server->authname,strerror(errno)) ;
288 inet_aton(opts->clientname, &client);
289 while (fgets(line,LINELEN,f)!=NULL) {
290 if((tmp=index(line, '/'))) {
291 if(strlen(line)<=tmp-line) {
292 msg4(LOG_CRIT, ERRMSG, line, opts->server->authname);
296 if(!inet_aton(line,&addr)) {
297 msg4(LOG_CRIT, ERRMSG, line, opts->server->authname);
300 len=strtol(tmp, NULL, 0);
301 addr.s_addr>>=32-len;
302 addr.s_addr<<=32-len;
303 memcpy(&cltemp,&client,sizeof(client));
304 cltemp.s_addr>>=32-len;
305 cltemp.s_addr<<=32-len;
306 if(addr.s_addr == cltemp.s_addr) {
310 if (strncmp(line,opts->clientname,strlen(opts->clientname))==0) {
320 * Read data from a file descriptor into a buffer
322 * @param f a file descriptor
323 * @param buf a buffer
324 * @param len the number of bytes to be read
326 static inline void readit(int f, void *buf, size_t len) {
330 if ((res = read(f, buf, len)) <= 0) {
331 if(errno != EAGAIN) {
332 err("Read failed: %m");
342 * Write data from a buffer into a filedescriptor
344 * @param f a file descriptor
345 * @param buf a buffer containing data
346 * @param len the number of bytes to be written
348 static inline void writeit(int f, void *buf, size_t len) {
352 if ((res = write(f, buf, len)) <= 0)
353 err("Send failed: %m");
360 * Print out a message about how to use nbd-server. Split out to a separate
361 * function so that we can call it from multiple places
364 printf("This is nbd-server version " VERSION "\n");
365 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"
366 "\t-r|--read-only\t\tread only\n"
367 "\t-m|--multi-file\t\tmultiple file\n"
368 "\t-c|--copy-on-write\tcopy on write\n"
369 "\t-C|--config-file\tspecify an alternate configuration file\n"
370 "\t-l|--authorize-file\tfile with list of hosts that are allowed to\n\t\t\t\tconnect.\n"
371 "\t-p|--pid-file\t\tspecify a filename to write our PID to\n"
372 "\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"
373 "\t-M|--max-connections\tspecify the maximum number of opened connections\n\n"
374 "\tif port is set to 0, stdin is used (for running from inetd)\n"
375 "\tif file_to_export contains '%%s', it is substituted with the IP\n"
376 "\t\taddress of the machine trying to connect\n"
377 "\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");
378 printf("Using configuration file %s\n", CFILE);
381 /* Dumps a config file section of the given SERVER*, and exits. */
382 void dump_section(SERVER* serve, gchar* section_header) {
383 printf("[%s]\n", section_header);
384 printf("\texportname = %s\n", serve->exportname);
385 printf("\tlistenaddr = %s\n", serve->listenaddr);
386 printf("\tport = %d\n", serve->port);
387 if(serve->flags & F_READONLY) {
388 printf("\treadonly = true\n");
390 if(serve->flags & F_MULTIFILE) {
391 printf("\tmultifile = true\n");
393 if(serve->flags & F_COPYONWRITE) {
394 printf("\tcopyonwrite = true\n");
396 if(serve->expected_size) {
397 printf("\tfilesize = %lld\n", (long long int)serve->expected_size);
399 if(serve->authname) {
400 printf("\tauthfile = %s\n", serve->authname);
406 * Parse the command line.
408 * @param argc the argc argument to main()
409 * @param argv the argv argument to main()
411 SERVER* cmdline(int argc, char *argv[]) {
415 struct option long_options[] = {
416 {"read-only", no_argument, NULL, 'r'},
417 {"multi-file", no_argument, NULL, 'm'},
418 {"copy-on-write", no_argument, NULL, 'c'},
419 {"dont-fork", no_argument, NULL, 'd'},
420 {"authorize-file", required_argument, NULL, 'l'},
421 {"config-file", required_argument, NULL, 'C'},
422 {"pid-file", required_argument, NULL, 'p'},
423 {"output-config", required_argument, NULL, 'o'},
424 {"max-connection", required_argument, NULL, 'M'},
431 gboolean do_output=FALSE;
432 gchar* section_header="";
438 serve=g_new0(SERVER, 1);
439 serve->authname = g_strdup(default_authname);
440 serve->virtstyle=VIRT_IPLIT;
441 while((c=getopt_long(argc, argv, "-C:cdl:mo:rp:M:", long_options, &i))>=0) {
444 /* non-option argument */
445 switch(nonspecial++) {
447 if(strchr(optarg, ':') == strrchr(optarg, ':')) {
448 addr_port=g_strsplit(optarg, ":", 2);
450 /* Check for "@" - maybe user using this separator
453 g_strfreev(addr_port);
454 addr_port=g_strsplit(optarg, "@", 2);
457 addr_port=g_strsplit(optarg, "@", 2);
461 serve->port=strtol(addr_port[1], NULL, 0);
462 serve->listenaddr=g_strdup(addr_port[0]);
464 serve->listenaddr=NULL;
465 serve->port=strtol(addr_port[0], NULL, 0);
467 g_strfreev(addr_port);
470 serve->exportname = g_strdup(optarg);
471 if(serve->exportname[0] != '/') {
472 fprintf(stderr, "E: The to be exported file needs to be an absolute filename!\n");
477 last=strlen(optarg)-1;
479 if (suffix == 'k' || suffix == 'K' ||
480 suffix == 'm' || suffix == 'M')
482 es = (off_t)atoll(optarg);
490 serve->expected_size = es;
495 serve->flags |= F_READONLY;
498 serve->flags |= F_MULTIFILE;
502 section_header = g_strdup(optarg);
505 strncpy(pidftemplate, optarg, 256);
508 serve->flags |=F_COPYONWRITE;
514 g_free(config_file_pos);
515 config_file_pos=g_strdup(optarg);
518 g_free(serve->authname);
519 serve->authname=g_strdup(optarg);
522 serve->max_connections = strtol(optarg, NULL, 0);
530 /* What's left: the port to export, the name of the to be exported
531 * file, and, optionally, the size of the file, in that order. */
540 g_critical("Need a complete configuration on the command line to output a config file section!");
543 dump_section(serve, section_header);
549 * Error codes for config file parsing
552 CFILE_NOTFOUND, /**< The configuration file is not found */
553 CFILE_MISSING_GENERIC, /**< The (required) group "generic" is missing */
554 CFILE_KEY_MISSING, /**< A (required) key is missing */
555 CFILE_VALUE_INVALID, /**< A value is syntactically invalid */
556 CFILE_VALUE_UNSUPPORTED,/**< A value is not supported in this build */
557 CFILE_PROGERR, /**< Programmer error */
558 CFILE_NO_EXPORTS, /**< A config file was specified that does not
559 define any exports */
560 CFILE_INCORRECT_PORT, /**< The reserved port was specified for an
565 * Remove a SERVER from memory. Used from the hash table
567 void remove_server(gpointer s) {
571 g_free(server->exportname);
573 g_free(server->authname);
574 if(server->listenaddr)
575 g_free(server->listenaddr);
577 g_free(server->prerun);
579 g_free(server->postrun);
585 * @param s the old server we want to duplicate
586 * @return new duplicated server
588 SERVER* dup_serve(SERVER *s) {
589 SERVER *serve = NULL;
591 serve=g_new0(SERVER, 1);
596 serve->exportname = g_strdup(s->exportname);
598 serve->expected_size = s->expected_size;
601 serve->listenaddr = g_strdup(s->listenaddr);
603 serve->port = s->port;
606 serve->authname = strdup(s->authname);
608 serve->flags = s->flags;
609 serve->socket = s->socket;
610 serve->socket_family = s->socket_family;
611 serve->virtstyle = s->virtstyle;
612 serve->cidrlen = s->cidrlen;
615 serve->prerun = g_strdup(s->prerun);
618 serve->postrun = g_strdup(s->postrun);
621 serve->servename = g_strdup(s->servename);
623 serve->max_connections = s->max_connections;
629 * append new server to array
631 * @param a server array
632 * @return 0 success, -1 error
634 int append_serve(SERVER *s, GArray *a) {
636 struct addrinfo hints;
637 struct addrinfo *ai = NULL;
638 struct addrinfo *rp = NULL;
639 char host[NI_MAXHOST];
645 err("Invalid parsing server");
649 port = g_strdup_printf("%d", s->port);
651 memset(&hints,'\0',sizeof(hints));
652 hints.ai_family = AF_UNSPEC;
653 hints.ai_socktype = SOCK_STREAM;
654 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
655 hints.ai_protocol = IPPROTO_TCP;
657 e = getaddrinfo(s->listenaddr, port, &hints, &ai);
663 for (rp = ai; rp != NULL; rp = rp->ai_next) {
664 e = getnameinfo(rp->ai_addr, rp->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
666 if (e != 0) { // error
667 fprintf(stderr, "getnameinfo: %s\n", gai_strerror(e));
671 // duplicate server and set listenaddr to resolved IP address
674 ns->listenaddr = g_strdup(host);
675 ns->socket_family = rp->ai_family;
676 g_array_append_val(a, *ns);
684 fprintf(stderr, "getaddrinfo failed on listen host/address: %s (%s)\n", s->listenaddr ? s->listenaddr : "any", gai_strerror(e));
695 * Parse the config file.
697 * @param f the name of the config file
698 * @param e a GError. @see CFILE_ERRORS for what error values this function can
700 * @return a Array of SERVER* pointers, If the config file is empty or does not
701 * exist, returns an empty GHashTable; if the config file contains an
702 * error, returns NULL, and e is set appropriately
704 GArray* parse_cfile(gchar* f, GError** e) {
705 const char* DEFAULT_ERROR = "Could not parse %s in group %s: %s";
706 const char* MISSING_REQUIRED_ERROR = "Could not find required value %s in group %s: %s";
708 gchar *virtstyle=NULL;
710 { "exportname", TRUE, PARAM_STRING, &(s.exportname), 0 },
711 { "port", TRUE, PARAM_INT, &(s.port), 0 },
712 { "authfile", FALSE, PARAM_STRING, &(s.authname), 0 },
713 { "filesize", FALSE, PARAM_INT, &(s.expected_size), 0 },
714 { "virtstyle", FALSE, PARAM_STRING, &(virtstyle), 0 },
715 { "prerun", FALSE, PARAM_STRING, &(s.prerun), 0 },
716 { "postrun", FALSE, PARAM_STRING, &(s.postrun), 0 },
717 { "readonly", FALSE, PARAM_BOOL, &(s.flags), F_READONLY },
718 { "multifile", FALSE, PARAM_BOOL, &(s.flags), F_MULTIFILE },
719 { "copyonwrite", FALSE, PARAM_BOOL, &(s.flags), F_COPYONWRITE },
720 { "sparse_cow", FALSE, PARAM_BOOL, &(s.flags), F_SPARSE },
721 { "sdp", FALSE, PARAM_BOOL, &(s.flags), F_SDP },
722 { "sync", FALSE, PARAM_BOOL, &(s.flags), F_SYNC },
723 { "listenaddr", FALSE, PARAM_STRING, &(s.listenaddr), 0 },
724 { "maxconnections", FALSE, PARAM_INT, &(s.max_connections), 0 },
726 const int lp_size=sizeof(lp)/sizeof(PARAM);
728 { "user", FALSE, PARAM_STRING, &runuser, 0 },
729 { "group", FALSE, PARAM_STRING, &rungroup, 0 },
730 { "oldstyle", FALSE, PARAM_BOOL, &do_oldstyle, 1 },
731 { "listenaddr", FALSE, PARAM_STRING, &modern_listen, 0 },
734 int p_size=sizeof(gp)/sizeof(PARAM);
737 const char *err_msg=NULL;
746 errdomain = g_quark_from_string("parse_cfile");
747 cfile = g_key_file_new();
748 retval = g_array_new(FALSE, TRUE, sizeof(SERVER));
749 if(!g_key_file_load_from_file(cfile, f, G_KEY_FILE_KEEP_COMMENTS |
750 G_KEY_FILE_KEEP_TRANSLATIONS, &err)) {
751 g_set_error(e, errdomain, CFILE_NOTFOUND, "Could not open config file %s.", f);
752 g_key_file_free(cfile);
755 startgroup = g_key_file_get_start_group(cfile);
756 if(!startgroup || strcmp(startgroup, "generic")) {
757 g_set_error(e, errdomain, CFILE_MISSING_GENERIC, "Config file does not contain the [generic] group!");
758 g_key_file_free(cfile);
761 groups = g_key_file_get_groups(cfile, NULL);
762 for(i=0;groups[i];i++) {
763 memset(&s, '\0', sizeof(SERVER));
765 /* After the [generic] group, start parsing exports */
770 for(j=0;j<p_size;j++) {
771 g_assert(p[j].target != NULL);
772 g_assert(p[j].ptype==PARAM_INT||p[j].ptype==PARAM_STRING||p[j].ptype==PARAM_BOOL);
775 *((gint*)p[j].target) =
776 g_key_file_get_integer(cfile,
782 *((gchar**)p[j].target) =
783 g_key_file_get_string(cfile,
789 value = g_key_file_get_boolean(cfile,
791 p[j].paramname, &err);
794 *((gint*)p[j].target) |= p[j].flagval;
796 *((gint*)p[j].target) &= ~(p[j].flagval);
801 if(!strcmp(p[j].paramname, "port") && !strcmp(p[j].target, NBD_DEFAULT_PORT)) {
802 g_set_error(e, errdomain, CFILE_INCORRECT_PORT, "Config file specifies default port for oldstyle export");
803 g_key_file_free(cfile);
807 if(err->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
809 /* Ignore not-found error for optional values */
813 err_msg = MISSING_REQUIRED_ERROR;
816 err_msg = DEFAULT_ERROR;
818 g_set_error(e, errdomain, CFILE_VALUE_INVALID, err_msg, p[j].paramname, groups[i], err->message);
819 g_array_free(retval, TRUE);
821 g_key_file_free(cfile);
826 if(!strncmp(virtstyle, "none", 4)) {
827 s.virtstyle=VIRT_NONE;
828 } else if(!strncmp(virtstyle, "ipliteral", 9)) {
829 s.virtstyle=VIRT_IPLIT;
830 } else if(!strncmp(virtstyle, "iphash", 6)) {
831 s.virtstyle=VIRT_IPHASH;
832 } else if(!strncmp(virtstyle, "cidrhash", 8)) {
833 s.virtstyle=VIRT_CIDR;
834 if(strlen(virtstyle)<10) {
835 g_set_error(e, errdomain, CFILE_VALUE_INVALID, "Invalid value %s for parameter virtstyle in group %s: missing length", virtstyle, groups[i]);
836 g_array_free(retval, TRUE);
837 g_key_file_free(cfile);
840 s.cidrlen=strtol(virtstyle+8, NULL, 0);
842 g_set_error(e, errdomain, CFILE_VALUE_INVALID, "Invalid value %s for parameter virtstyle in group %s", virtstyle, groups[i]);
843 g_array_free(retval, TRUE);
844 g_key_file_free(cfile);
847 if(s.port && !do_oldstyle) {
848 g_warning("A port was specified, but oldstyle exports were not requested. This may not do what you expect.");
849 g_warning("Please read 'man 5 nbd-server' and search for oldstyle for more info");
852 s.virtstyle=VIRT_IPLIT;
854 /* Don't need to free this, it's not our string */
856 /* Don't append values for the [generic] group */
858 s.socket_family = AF_UNSPEC;
859 s.servename = groups[i];
861 append_serve(&s, retval);
868 if(s.flags & F_SDP) {
869 g_set_error(e, errdomain, CFILE_VALUE_UNSUPPORTED, "This nbd-server was built without support for SDP, yet group %s uses it", groups[i]);
870 g_array_free(retval, TRUE);
871 g_key_file_free(cfile);
877 g_set_error(e, errdomain, CFILE_NO_EXPORTS, "The config file does not specify any exports");
879 g_key_file_free(cfile);
884 * Signal handler for SIGCHLD
885 * @param s the signal we're handling (must be SIGCHLD, or something
888 void sigchld_handler(int s) {
893 while((pid=waitpid(-1, &status, WNOHANG)) > 0) {
894 if(WIFEXITED(status)) {
895 msg3(LOG_INFO, "Child exited with %d", WEXITSTATUS(status));
897 i=g_hash_table_lookup(children, &pid);
899 msg3(LOG_INFO, "SIGCHLD received for an unknown child with PID %ld", (long)pid);
901 DEBUG2("Removing %d from the list of children", pid);
902 g_hash_table_remove(children, &pid);
908 * Kill a child. Called from sigterm_handler::g_hash_table_foreach.
911 * @param value the value corresponding to the above key
912 * @param user_data a pointer which we always set to 1, so that we know what
915 void killchild(gpointer key, gpointer value, gpointer user_data) {
917 int *parent=user_data;
924 * Handle SIGTERM and dispatch it to our children
925 * @param s the signal we're handling (must be SIGTERM, or something
926 * is severely wrong).
928 void sigterm_handler(int s) {
931 g_hash_table_foreach(children, killchild, &parent);
941 * Detect the size of a file.
943 * @param fhandle An open filedescriptor
944 * @return the size of the file, or OFFT_MAX if detection was
947 off_t size_autodetect(int fhandle) {
950 struct stat stat_buf;
953 #ifdef HAVE_SYS_MOUNT_H
954 #ifdef HAVE_SYS_IOCTL_H
956 DEBUG("looking for export size with ioctl BLKGETSIZE64\n");
957 if (!ioctl(fhandle, BLKGETSIZE64, &bytes) && bytes) {
960 #endif /* BLKGETSIZE64 */
961 #endif /* HAVE_SYS_IOCTL_H */
962 #endif /* HAVE_SYS_MOUNT_H */
964 DEBUG("looking for fhandle size with fstat\n");
965 stat_buf.st_size = 0;
966 error = fstat(fhandle, &stat_buf);
968 if(stat_buf.st_size > 0)
969 return (off_t)stat_buf.st_size;
971 err("fstat failed: %m");
974 DEBUG("looking for fhandle size with lseek SEEK_END\n");
975 es = lseek(fhandle, (off_t)0, SEEK_END);
976 if (es > ((off_t)0)) {
979 DEBUG2("lseek failed: %d", errno==EBADF?1:(errno==ESPIPE?2:(errno==EINVAL?3:4)));
982 err("Could not find size of exported block device: %m");
987 * Get the file handle and offset, given an export offset.
989 * @param export An array of export files
990 * @param a The offset to get corresponding file/offset for
991 * @param fhandle [out] File descriptor
992 * @param foffset [out] Offset into fhandle
993 * @param maxbytes [out] Tells how many bytes can be read/written
994 * from fhandle starting at foffset (0 if there is no limit)
995 * @return 0 on success, -1 on failure
997 int get_filepos(GArray* export, off_t a, int* fhandle, off_t* foffset, size_t* maxbytes ) {
998 /* Negative offset not allowed */
1002 /* Binary search for last file with starting offset <= a */
1005 int end = export->len - 1;
1006 while( start <= end ) {
1007 int mid = (start + end) / 2;
1008 fi = g_array_index(export, FILE_INFO, mid);
1009 if( fi.startoff < a ) {
1011 } else if( fi.startoff > a ) {
1019 /* end should never go negative, since first startoff is 0 and a >= 0 */
1022 fi = g_array_index(export, FILE_INFO, end);
1023 *fhandle = fi.fhandle;
1024 *foffset = a - fi.startoff;
1026 if( end+1 < export->len ) {
1027 FILE_INFO fi_next = g_array_index(export, FILE_INFO, end+1);
1028 *maxbytes = fi_next.startoff - a;
1035 * seek to a position in a file, with error handling.
1036 * @param handle a filedescriptor
1037 * @param a position to seek to
1038 * @todo get rid of this; lastpoint is a global variable right now, but it
1039 * shouldn't be. If we pass it on as a parameter, that makes things a *lot*
1042 void myseek(int handle,off_t a) {
1043 if (lseek(handle, a, SEEK_SET) < 0) {
1044 err("Can not seek locally!\n");
1049 * Write an amount of bytes at a given offset to the right file. This
1050 * abstracts the write-side of the multiple file option.
1052 * @param a The offset where the write should start
1053 * @param buf The buffer to write from
1054 * @param len The length of buf
1055 * @param client The client we're serving for
1056 * @return The number of bytes actually written, or -1 in case of an error
1058 ssize_t rawexpwrite(off_t a, char *buf, size_t len, CLIENT *client) {
1064 if(get_filepos(client->export, a, &fhandle, &foffset, &maxbytes))
1066 if(maxbytes && len > maxbytes)
1069 DEBUG4("(WRITE to fd %d offset %llu len %u), ", fhandle, foffset, len);
1071 myseek(fhandle, foffset);
1072 retval = write(fhandle, buf, len);
1073 if(client->server->flags & F_SYNC) {
1080 * Call rawexpwrite repeatedly until all data has been written.
1081 * @return 0 on success, nonzero on failure
1083 int rawexpwrite_fully(off_t a, char *buf, size_t len, CLIENT *client) {
1086 while(len > 0 && (ret=rawexpwrite(a, buf, len, client)) > 0 ) {
1091 return (ret < 0 || len != 0);
1095 * Read an amount of bytes at a given offset from the right file. This
1096 * abstracts the read-side of the multiple files option.
1098 * @param a The offset where the read should start
1099 * @param buf A buffer to read into
1100 * @param len The size of buf
1101 * @param client The client we're serving for
1102 * @return The number of bytes actually read, or -1 in case of an
1105 ssize_t rawexpread(off_t a, char *buf, size_t len, CLIENT *client) {
1110 if(get_filepos(client->export, a, &fhandle, &foffset, &maxbytes))
1112 if(maxbytes && len > maxbytes)
1115 DEBUG4("(READ from fd %d offset %llu len %u), ", fhandle, foffset, len);
1117 myseek(fhandle, foffset);
1118 return read(fhandle, buf, len);
1122 * Call rawexpread repeatedly until all data has been read.
1123 * @return 0 on success, nonzero on failure
1125 int rawexpread_fully(off_t a, char *buf, size_t len, CLIENT *client) {
1128 while(len > 0 && (ret=rawexpread(a, buf, len, client)) > 0 ) {
1133 return (ret < 0 || len != 0);
1137 * Read an amount of bytes at a given offset from the right file. This
1138 * abstracts the read-side of the copyonwrite stuff, and calls
1139 * rawexpread() with the right parameters to do the actual work.
1140 * @param a The offset where the read should start
1141 * @param buf A buffer to read into
1142 * @param len The size of buf
1143 * @param client The client we're going to read for
1144 * @return 0 on success, nonzero on failure
1146 int expread(off_t a, char *buf, size_t len, CLIENT *client) {
1147 off_t rdlen, offset;
1148 off_t mapcnt, mapl, maph, pagestart;
1150 if (!(client->server->flags & F_COPYONWRITE))
1151 return(rawexpread_fully(a, buf, len, client));
1152 DEBUG3("Asked to read %d bytes at %llu.\n", len, (unsigned long long)a);
1154 mapl=a/DIFFPAGESIZE; maph=(a+len-1)/DIFFPAGESIZE;
1156 for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
1157 pagestart=mapcnt*DIFFPAGESIZE;
1159 rdlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
1160 len : (size_t)DIFFPAGESIZE-offset;
1161 if (client->difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
1162 DEBUG3("Page %llu is at %lu\n", (unsigned long long)mapcnt,
1163 (unsigned long)(client->difmap[mapcnt]));
1164 myseek(client->difffile, client->difmap[mapcnt]*DIFFPAGESIZE+offset);
1165 if (read(client->difffile, buf, rdlen) != rdlen) return -1;
1166 } else { /* the block is not there */
1167 DEBUG2("Page %llu is not here, we read the original one\n",
1168 (unsigned long long)mapcnt);
1169 if(rawexpread_fully(a, buf, rdlen, client)) return -1;
1171 len-=rdlen; a+=rdlen; buf+=rdlen;
1177 * Write an amount of bytes at a given offset to the right file. This
1178 * abstracts the write-side of the copyonwrite option, and calls
1179 * rawexpwrite() with the right parameters to do the actual work.
1181 * @param a The offset where the write should start
1182 * @param buf The buffer to write from
1183 * @param len The length of buf
1184 * @param client The client we're going to write for.
1185 * @return 0 on success, nonzero on failure
1187 int expwrite(off_t a, char *buf, size_t len, CLIENT *client) {
1188 char pagebuf[DIFFPAGESIZE];
1189 off_t mapcnt,mapl,maph;
1194 if (!(client->server->flags & F_COPYONWRITE))
1195 return(rawexpwrite_fully(a, buf, len, client));
1196 DEBUG3("Asked to write %d bytes at %llu.\n", len, (unsigned long long)a);
1198 mapl=a/DIFFPAGESIZE ; maph=(a+len-1)/DIFFPAGESIZE ;
1200 for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
1201 pagestart=mapcnt*DIFFPAGESIZE ;
1202 offset=a-pagestart ;
1203 wrlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
1204 len : (size_t)DIFFPAGESIZE-offset;
1206 if (client->difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
1207 DEBUG3("Page %llu is at %lu\n", (unsigned long long)mapcnt,
1208 (unsigned long)(client->difmap[mapcnt])) ;
1209 myseek(client->difffile,
1210 client->difmap[mapcnt]*DIFFPAGESIZE+offset);
1211 if (write(client->difffile, buf, wrlen) != wrlen) return -1 ;
1212 } else { /* the block is not there */
1213 myseek(client->difffile,client->difffilelen*DIFFPAGESIZE) ;
1214 client->difmap[mapcnt]=(client->server->flags&F_SPARSE)?mapcnt:client->difffilelen++;
1215 DEBUG3("Page %llu is not here, we put it at %lu\n",
1216 (unsigned long long)mapcnt,
1217 (unsigned long)(client->difmap[mapcnt]));
1218 rdlen=DIFFPAGESIZE ;
1219 if (rawexpread_fully(pagestart, pagebuf, rdlen, client))
1221 memcpy(pagebuf+offset,buf,wrlen) ;
1222 if (write(client->difffile, pagebuf, DIFFPAGESIZE) !=
1226 len-=wrlen ; a+=wrlen ; buf+=wrlen ;
1232 * Do the initial negotiation.
1234 * @param client The client we're negotiating with.
1236 CLIENT* negotiate(int net, CLIENT *client, GArray* servers) {
1239 uint32_t flags = NBD_FLAG_HAS_FLAGS;
1240 uint16_t smallflags = 0;
1243 memset(zeros, '\0', sizeof(zeros));
1244 if(!client || !client->modern) {
1246 if (write(net, INIT_PASSWD, 8) < 0) {
1247 err_nonfatal("Negotiation failed: %m");
1251 if(!client || client->modern) {
1253 magic = htonll(opts_magic);
1256 magic = htonll(cliserv_magic);
1258 if (write(net, &magic, sizeof(magic)) < 0) {
1259 err_nonfatal("Negotiation failed: %m");
1273 err("programmer error");
1274 if (write(net, &smallflags, sizeof(uint16_t)) < 0)
1275 err("Negotiation failed: %m");
1276 if (read(net, &reserved, sizeof(reserved)) < 0)
1277 err("Negotiation failed: %m");
1278 if (read(net, &magic, sizeof(magic)) < 0)
1279 err("Negotiation failed: %m");
1280 magic = ntohll(magic);
1281 if(magic != opts_magic) {
1285 if (read(net, &opt, sizeof(opt)) < 0)
1286 err("Negotiation failed: %m");
1288 if(opt != NBD_OPT_EXPORT_NAME) {
1292 if (read(net, &namelen, sizeof(namelen)) < 0)
1293 err("Negotiation failed: %m");
1294 namelen = ntohl(namelen);
1295 name = malloc(namelen+1);
1297 if (read(net, name, namelen) < 0)
1298 err("Negotiation failed: %m");
1299 for(i=0; i<servers->len; i++) {
1300 SERVER* serve = &(g_array_index(servers, SERVER, i));
1301 if(!strcmp(serve->servename, name)) {
1302 CLIENT* client = g_new0(CLIENT, 1);
1303 client->server = serve;
1304 client->exportsize = OFFT_MAX;
1306 client->modern = TRUE;
1315 size_host = htonll((u64)(client->exportsize));
1316 if (write(net, &size_host, 8) < 0)
1317 err("Negotiation failed: %m");
1318 if (client->server->flags & F_READONLY)
1319 flags |= NBD_FLAG_READ_ONLY;
1320 if (!client->modern) {
1322 flags = htonl(flags);
1323 if (write(client->net, &flags, 4) < 0)
1324 err("Negotiation failed: %m");
1327 smallflags = (uint16_t)(flags & ~((uint16_t)0));
1328 smallflags = htons(smallflags);
1329 if (write(client->net, &smallflags, sizeof(smallflags)) < 0) {
1330 err("Negotiation failed: %m");
1334 if (write(client->net, zeros, 124) < 0)
1335 err("Negotiation failed: %m");
1339 /** sending macro. */
1340 #define SEND(net,reply) writeit( net, &reply, sizeof( reply ));
1342 #define ERROR(client,reply,errcode) { reply.error = htonl(errcode); SEND(client->net,reply); reply.error = 0; }
1344 * Serve a file to a single client.
1346 * @todo This beast needs to be split up in many tiny little manageable
1347 * pieces. Preferably with a chainsaw.
1349 * @param client The client we're going to serve to.
1350 * @return when the client disconnects
1352 int mainloop(CLIENT *client) {
1353 struct nbd_request request;
1354 struct nbd_reply reply;
1355 gboolean go_on=TRUE;
1359 negotiate(client->net, client, NULL);
1360 DEBUG("Entering request loop!\n");
1361 reply.magic = htonl(NBD_REPLY_MAGIC);
1373 readit(client->net, &request, sizeof(request));
1374 request.from = ntohll(request.from);
1375 request.type = ntohl(request.type);
1377 if (request.type==NBD_CMD_DISC) {
1378 msg2(LOG_INFO, "Disconnect request received.");
1379 if (client->server->flags & F_COPYONWRITE) {
1380 if (client->difmap) g_free(client->difmap) ;
1381 close(client->difffile);
1382 unlink(client->difffilename);
1383 free(client->difffilename);
1389 len = ntohl(request.len);
1391 if (request.magic != htonl(NBD_REQUEST_MAGIC))
1392 err("Not enough magic.");
1393 if (len > BUFSIZE - sizeof(struct nbd_reply)) {
1394 currlen = BUFSIZE - sizeof(struct nbd_reply);
1395 msg2(LOG_INFO, "oversized request (this is not a problem)");
1400 printf("%s from %llu (%llu) len %d, ", request.type ? "WRITE" :
1401 "READ", (unsigned long long)request.from,
1402 (unsigned long long)request.from / 512, len);
1404 memcpy(reply.handle, request.handle, sizeof(reply.handle));
1405 if ((request.from + len) > (OFFT_MAX)) {
1406 DEBUG("[Number too large!]");
1407 ERROR(client, reply, EINVAL);
1411 if (((ssize_t)((off_t)request.from + len) > client->exportsize)) {
1413 ERROR(client, reply, EINVAL);
1417 if (request.type==NBD_CMD_WRITE) {
1418 DEBUG("wr: net->buf, ");
1420 readit(client->net, buf, currlen);
1421 DEBUG("buf->exp, ");
1422 if ((client->server->flags & F_READONLY) ||
1423 (client->server->flags & F_AUTOREADONLY)) {
1424 DEBUG("[WRITE to READONLY!]");
1425 ERROR(client, reply, EPERM);
1428 if (expwrite(request.from, buf, len, client)) {
1429 DEBUG("Write failed: %m" );
1430 ERROR(client, reply, errno);
1433 SEND(client->net, reply);
1436 currlen = (len < BUFSIZE) ? len : BUFSIZE;
1442 DEBUG("exp->buf, ");
1443 memcpy(buf, &reply, sizeof(struct nbd_reply));
1444 p = buf + sizeof(struct nbd_reply);
1445 writelen = currlen + sizeof(struct nbd_reply);
1447 if (expread(request.from, p, currlen, client)) {
1448 DEBUG("Read failed: %m");
1449 ERROR(client, reply, errno);
1453 DEBUG("buf->net, ");
1454 writeit(client->net, buf, writelen);
1456 currlen = (len < BUFSIZE) ? len : BUFSIZE;
1466 * Set up client export array, which is an array of FILE_INFO.
1467 * Also, split a single exportfile into multiple ones, if that was asked.
1468 * @param client information on the client which we want to setup export for
1470 void setupexport(CLIENT* client) {
1472 off_t laststartoff = 0, lastsize = 0;
1473 int multifile = (client->server->flags & F_MULTIFILE);
1475 client->export = g_array_new(TRUE, TRUE, sizeof(FILE_INFO));
1477 /* If multi-file, open as many files as we can.
1478 * If not, open exactly one file.
1479 * Calculate file sizes as we go to get total size. */
1483 gchar* error_string;
1484 mode_t mode = (client->server->flags & F_READONLY) ? O_RDONLY : O_RDWR;
1487 tmpname=g_strdup_printf("%s.%d", client->exportname, i);
1489 tmpname=g_strdup(client->exportname);
1491 DEBUG2( "Opening %s\n", tmpname );
1492 fi.fhandle = open(tmpname, mode);
1493 if(fi.fhandle == -1 && mode == O_RDWR) {
1494 /* Try again because maybe media was read-only */
1495 fi.fhandle = open(tmpname, O_RDONLY);
1496 if(fi.fhandle != -1) {
1497 /* Opening the base file in copyonwrite mode is
1499 if(!(client->server->flags & F_COPYONWRITE)) {
1500 client->server->flags |= F_AUTOREADONLY;
1501 client->server->flags |= F_READONLY;
1505 if(fi.fhandle == -1) {
1506 if(multifile && i>0)
1508 error_string=g_strdup_printf(
1509 "Could not open exported file %s: %%m",
1513 fi.startoff = laststartoff + lastsize;
1514 g_array_append_val(client->export, fi);
1517 /* Starting offset and size of this file will be used to
1518 * calculate starting offset of next file */
1519 laststartoff = fi.startoff;
1520 lastsize = size_autodetect(fi.fhandle);
1526 /* Set export size to total calculated size */
1527 client->exportsize = laststartoff + lastsize;
1529 /* Export size may be overridden */
1530 if(client->server->expected_size) {
1531 /* desired size must be <= total calculated size */
1532 if(client->server->expected_size > client->exportsize) {
1533 err("Size of exported file is too big\n");
1536 client->exportsize = client->server->expected_size;
1539 msg3(LOG_INFO, "Size of exported file/device is %llu", (unsigned long long)client->exportsize);
1541 msg3(LOG_INFO, "Total number of files: %d", i);
1545 int copyonwrite_prepare(CLIENT* client) {
1547 if ((client->difffilename = malloc(1024))==NULL)
1548 err("Failed to allocate string for diff file name");
1549 snprintf(client->difffilename, 1024, "%s-%s-%d.diff",client->exportname,client->clientname,
1551 client->difffilename[1023]='\0';
1552 msg3(LOG_INFO,"About to create map and diff file %s",client->difffilename) ;
1553 client->difffile=open(client->difffilename,O_RDWR | O_CREAT | O_TRUNC,0600) ;
1554 if (client->difffile<0) err("Could not create diff file (%m)") ;
1555 if ((client->difmap=calloc(client->exportsize/DIFFPAGESIZE,sizeof(u32)))==NULL)
1556 err("Could not allocate memory") ;
1557 for (i=0;i<client->exportsize/DIFFPAGESIZE;i++) client->difmap[i]=(u32)-1 ;
1563 * Run a command. This is used for the ``prerun'' and ``postrun'' config file
1566 * @param command the command to be ran. Read from the config file
1567 * @param file the file name we're about to export
1569 int do_run(gchar* command, gchar* file) {
1573 if(command && *command) {
1574 cmd = g_strdup_printf(command, file);
1582 * Serve a connection.
1584 * @todo allow for multithreading, perhaps use libevent. Not just yet, though;
1585 * follow the road map.
1587 * @param client a connected client
1589 void serveconnection(CLIENT *client) {
1590 if(do_run(client->server->prerun, client->exportname)) {
1593 setupexport(client);
1595 if (client->server->flags & F_COPYONWRITE) {
1596 copyonwrite_prepare(client);
1599 setmysockopt(client->net);
1602 do_run(client->server->postrun, client->exportname);
1606 * Find the name of the file we have to serve. This will use g_strdup_printf
1607 * to put the IP address of the client inside a filename containing
1608 * "%s" (in the form as specified by the "virtstyle" option). That name
1609 * is then written to client->exportname.
1611 * @param net A socket connected to an nbd client
1612 * @param client information about the client. The IP address in human-readable
1613 * format will be written to a new char* buffer, the address of which will be
1614 * stored in client->clientname.
1616 void set_peername(int net, CLIENT *client) {
1617 struct sockaddr_storage addrin;
1618 struct sockaddr_storage netaddr;
1619 struct sockaddr_in *netaddr4 = NULL;
1620 struct sockaddr_in6 *netaddr6 = NULL;
1621 size_t addrinlen = sizeof( addrin );
1622 struct addrinfo hints;
1623 struct addrinfo *ai = NULL;
1624 char peername[NI_MAXHOST];
1625 char netname[NI_MAXHOST];
1631 if (getpeername(net, (struct sockaddr *) &addrin, (socklen_t *)&addrinlen) < 0)
1632 err("getsockname failed: %m");
1634 getnameinfo((struct sockaddr *)&addrin, (socklen_t)addrinlen,
1635 peername, sizeof (peername), NULL, 0, NI_NUMERICHOST);
1637 memset(&hints, '\0', sizeof (hints));
1638 hints.ai_flags = AI_ADDRCONFIG;
1639 e = getaddrinfo(peername, NULL, &hints, &ai);
1642 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
1647 switch(client->server->virtstyle) {
1649 client->exportname=g_strdup(client->server->exportname);
1652 for(i=0;i<strlen(peername);i++) {
1653 if(peername[i]=='.') {
1658 client->exportname=g_strdup_printf(client->server->exportname, peername);
1661 memcpy(&netaddr, &addrin, addrinlen);
1662 if(ai->ai_family == AF_INET) {
1663 netaddr4 = (struct sockaddr_in *)&netaddr;
1664 (netaddr4->sin_addr).s_addr>>=32-(client->server->cidrlen);
1665 (netaddr4->sin_addr).s_addr<<=32-(client->server->cidrlen);
1667 getnameinfo((struct sockaddr *) netaddr4, (socklen_t) addrinlen,
1668 netname, sizeof (netname), NULL, 0, NI_NUMERICHOST);
1669 tmp=g_strdup_printf("%s/%s", netname, peername);
1670 }else if(ai->ai_family == AF_INET6) {
1671 netaddr6 = (struct sockaddr_in6 *)&netaddr;
1673 shift = 128-(client->server->cidrlen);
1675 while(shift >= 32) {
1676 ((netaddr6->sin6_addr).s6_addr32[i])=0;
1680 (netaddr6->sin6_addr).s6_addr32[i]>>=shift;
1681 (netaddr6->sin6_addr).s6_addr32[i]<<=shift;
1683 getnameinfo((struct sockaddr *)netaddr6, (socklen_t)addrinlen,
1684 netname, sizeof(netname), NULL, 0, NI_NUMERICHOST);
1685 tmp=g_strdup_printf("%s/%s", netname, peername);
1689 client->exportname=g_strdup_printf(client->server->exportname, tmp);
1695 msg4(LOG_INFO, "connect from %s, assigned file is %s",
1696 peername, client->exportname);
1697 client->clientname=g_strdup(peername);
1702 * @param data a pointer to pid_t which should be freed
1704 void destroy_pid_t(gpointer data) {
1709 * Loop through the available servers, and serve them. Never returns.
1711 int serveloop(GArray* servers) {
1712 struct sockaddr_storage addrin;
1713 socklen_t addrinlen=sizeof(addrin);
1721 * Set up the master fd_set. The set of descriptors we need
1722 * to select() for never changes anyway and it buys us a *lot*
1723 * of time to only build this once. However, if we ever choose
1724 * to not fork() for clients anymore, we may have to revisit
1729 for(i=0;i<servers->len;i++) {
1730 if((sock=(g_array_index(servers, SERVER, i)).socket)) {
1731 FD_SET(sock, &mset);
1732 max=sock>max?sock:max;
1736 FD_SET(modernsock, &mset);
1737 max=modernsock>max?modernsock:max;
1740 CLIENT *client = NULL;
1743 memcpy(&rset, &mset, sizeof(fd_set));
1744 if(select(max+1, &rset, NULL, NULL, NULL)>0) {
1749 if(FD_ISSET(modernsock, &rset)) {
1750 if((net=accept(modernsock, (struct sockaddr *) &addrin, &addrinlen)) < 0)
1752 client = negotiate(net, NULL, servers);
1754 err_nonfatal("negotiation failed");
1759 serve = client->server;
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));
1799 if ((*pid=fork())<0) {
1800 msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ;
1804 if (*pid>0) { /* parent */
1806 g_hash_table_insert(children, pid, pid);
1810 g_hash_table_destroy(children);
1811 for(i=0;i<servers->len;i++) {
1812 serve=&g_array_index(servers, SERVER, i);
1813 close(serve->socket);
1815 /* FALSE does not free the
1816 actual data. This is required,
1817 because the client has a
1818 direct reference into that
1819 data, and otherwise we get a
1821 g_array_free(servers, FALSE);
1824 msg2(LOG_INFO,"Starting to serve");
1825 serveconnection(client);
1832 void dosockopts(int socket) {
1840 /* lose the pesky "Address already in use" error message */
1841 if (setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
1842 err("setsockopt SO_REUSEADDR");
1844 if (setsockopt(socket,SOL_SOCKET,SO_KEEPALIVE,&yes,sizeof(int)) == -1) {
1845 err("setsockopt SO_KEEPALIVE");
1848 /* make the listening socket non-blocking */
1849 if ((sock_flags = fcntl(socket, F_GETFL, 0)) == -1) {
1850 err("fcntl F_GETFL");
1852 if (fcntl(socket, F_SETFL, sock_flags | O_NONBLOCK) == -1) {
1853 err("fcntl F_SETFL O_NONBLOCK");
1858 * Connect a server's socket.
1860 * @param serve the server we want to connect.
1862 int setup_serve(SERVER *serve) {
1863 struct addrinfo hints;
1864 struct addrinfo *ai = NULL;
1869 return serve->servename ? 1 : 0;
1871 memset(&hints,'\0',sizeof(hints));
1872 hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG | AI_NUMERICSERV;
1873 hints.ai_socktype = SOCK_STREAM;
1874 hints.ai_family = serve->socket_family;
1876 port = g_strdup_printf ("%d", serve->port);
1880 e = getaddrinfo(serve->listenaddr,port,&hints,&ai);
1885 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
1891 if(serve->socket_family == AF_UNSPEC)
1892 serve->socket_family = ai->ai_family;
1895 if ((serve->flags) && F_SDP) {
1896 if (ai->ai_family == AF_INET)
1897 ai->ai_family = AF_INET_SDP;
1898 else (ai->ai_family == AF_INET6)
1899 ai->ai_family = AF_INET6_SDP;
1902 if ((serve->socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0)
1905 dosockopts(serve->socket);
1907 DEBUG("Waiting for connections... bind, ");
1908 e = bind(serve->socket, ai->ai_addr, ai->ai_addrlen);
1909 if (e != 0 && errno != EADDRINUSE)
1912 if (listen(serve->socket, 1) < 0)
1916 if(serve->servename) {
1923 void open_modern(void) {
1924 struct addrinfo hints;
1925 struct addrinfo* ai = NULL;
1929 memset(&hints, '\0', sizeof(hints));
1930 hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
1931 hints.ai_socktype = SOCK_STREAM;
1932 hints.ai_family = AF_UNSPEC;
1933 hints.ai_protocol = IPPROTO_TCP;
1934 e = getaddrinfo(modern_listen, NBD_DEFAULT_PORT, &hints, &ai);
1936 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
1939 if((modernsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))<0) {
1943 dosockopts(modernsock);
1945 if(bind(modernsock, ai->ai_addr, ai->ai_addrlen)) {
1948 if(listen(modernsock, 10) <0) {
1956 * Connect our servers.
1958 void setup_servers(GArray* servers) {
1960 struct sigaction sa;
1963 for(i=0;i<servers->len;i++) {
1964 want_modern |= setup_serve(&(g_array_index(servers, SERVER, i)));
1969 children=g_hash_table_new_full(g_int_hash, g_int_equal, NULL, destroy_pid_t);
1971 sa.sa_handler = sigchld_handler;
1972 sigemptyset(&sa.sa_mask);
1973 sa.sa_flags = SA_RESTART;
1974 if(sigaction(SIGCHLD, &sa, NULL) == -1)
1975 err("sigaction: %m");
1976 sa.sa_handler = sigterm_handler;
1977 sigemptyset(&sa.sa_mask);
1978 sa.sa_flags = SA_RESTART;
1979 if(sigaction(SIGTERM, &sa, NULL) == -1)
1980 err("sigaction: %m");
1984 * Go daemon (unless we specified at compile time that we didn't want this)
1985 * @param serve the first server of our configuration. If its port is zero,
1986 * then do not daemonize, because we're doing inetd then. This parameter
1987 * is only used to create a PID file of the form
1988 * /var/run/nbd-server.<port>.pid; it's not modified in any way.
1990 #if !defined(NODAEMON)
1991 void daemonize(SERVER* serve) {
1994 if(serve && !(serve->port)) {
2000 if(!*pidftemplate) {
2002 strncpy(pidftemplate, "/var/run/nbd-server.%d.pid", 255);
2004 strncpy(pidftemplate, "/var/run/nbd-server.pid", 255);
2007 snprintf(pidfname, 255, pidftemplate, serve ? serve->port : 0);
2008 pidf=fopen(pidfname, "w");
2010 fprintf(pidf,"%d\n", (int)getpid());
2014 fprintf(stderr, "Not fatal; continuing");
2018 #define daemonize(serve)
2019 #endif /* !defined(NODAEMON) */
2022 * Everything beyond this point (in the file) is run in non-daemon mode.
2023 * The stuff above daemonize() isn't.
2026 void serve_err(SERVER* serve, const char* msg) G_GNUC_NORETURN;
2028 void serve_err(SERVER* serve, const char* msg) {
2029 g_message("Export of %s on port %d failed:", serve->exportname,
2035 * Set up user-ID and/or group-ID
2037 void dousers(void) {
2042 gr=getgrnam(rungroup);
2044 str = g_strdup_printf("Invalid group name: %s", rungroup);
2047 if(setgid(gr->gr_gid)<0) {
2048 err("Could not set GID: %m");
2052 pw=getpwnam(runuser);
2054 str = g_strdup_printf("Invalid user name: %s", runuser);
2057 if(setuid(pw->pw_uid)<0) {
2058 err("Could not set UID: %m");
2064 void glib_message_syslog_redirect(const gchar *log_domain,
2065 GLogLevelFlags log_level,
2066 const gchar *message,
2069 int level=LOG_DEBUG;
2073 case G_LOG_FLAG_FATAL:
2074 case G_LOG_LEVEL_CRITICAL:
2075 case G_LOG_LEVEL_ERROR:
2078 case G_LOG_LEVEL_WARNING:
2081 case G_LOG_LEVEL_MESSAGE:
2082 case G_LOG_LEVEL_INFO:
2085 case G_LOG_LEVEL_DEBUG:
2090 syslog(level, "%s", message);
2095 * Main entry point...
2097 int main(int argc, char *argv[]) {
2102 if (sizeof( struct nbd_request )!=28) {
2103 fprintf(stderr,"Bad size of structure. Alignment problems?\n");
2104 exit(EXIT_FAILURE) ;
2107 memset(pidftemplate, '\0', 256);
2110 config_file_pos = g_strdup(CFILE);
2111 serve=cmdline(argc, argv);
2112 servers = parse_cfile(config_file_pos, &err);
2115 serve->socket_family = AF_UNSPEC;
2117 append_serve(serve, servers);
2119 if (!(serve->port)) {
2122 /* You really should define ISSERVER if you're going to use
2123 * inetd mode, but if you don't, closing stdout and stderr
2124 * (which inetd had connected to the client socket) will let it
2128 open("/dev/null", O_WRONLY);
2129 open("/dev/null", O_WRONLY);
2130 g_log_set_default_handler( glib_message_syslog_redirect, NULL );
2132 client=g_malloc(sizeof(CLIENT));
2133 client->server=serve;
2135 client->exportsize=OFFT_MAX;
2136 set_peername(0,client);
2137 serveconnection(client);
2142 if(!servers || !servers->len) {
2143 if(err && !(err->domain == g_quark_from_string("parse_cfile")
2144 && err->code == CFILE_NOTFOUND)) {
2145 g_warning("Could not parse config file: %s",
2146 err ? err->message : "Unknown error");
2150 g_warning("Specifying an export on the command line is deprecated.");
2151 g_warning("Please use a configuration file instead.");
2154 if((!serve) && (!servers||!servers->len)) {
2155 g_message("No configured exports; quitting.");
2160 setup_servers(servers);