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 (not released (yet?)).
49 * 11/02/2004 - Doxygenified the source, modularized it a bit. Needs a
50 * lot more work, but this is a start. Wouter Verhelst
54 /* Includes LFS defines, which defines behaviours of some of the following
55 * headers, so must come before those */
59 #include <sys/types.h>
60 #include <sys/socket.h>
62 #include <sys/wait.h> /* wait */
63 #ifdef HAVE_SYS_IOCTL_H
64 #include <sys/ioctl.h>
66 #include <sys/param.h>
67 #ifdef HAVE_SYS_MOUNT_H
68 #include <sys/mount.h> /* For BLKGETSIZE */
70 #include <signal.h> /* sigaction */
71 #include <netinet/tcp.h>
72 #include <netinet/in.h> /* sockaddr_in, htons, in_addr */
73 #include <netdb.h> /* hostent, gethostby*, getservby* */
80 #include <arpa/inet.h>
86 /* used in cliserv.h, so must come first */
87 #define MY_NAME "nbd_server"
90 /** how much space for child PIDs we have by default. Dynamically
91 allocated, and will be realloc()ed if out of space, so this should
92 probably be fair for most situations. */
93 #define DEFAULT_CHILD_ARRAY 256
95 /** Logging macros, now nothing goes to syslog unless you say ISSERVER */
97 #define msg2(a,b) syslog(a,"%s", b)
98 #define msg3(a,b,c) syslog(a,"%s %s", b,c)
99 #define msg4(a,b,c,d) syslog(a,"%s %s %s", b,c,d)
101 #define msg2(a,b) do { fprintf(stderr,"%s\n", b) ; } while(0)
102 #define msg3(a,b,c) do { fprintf(stderr,"%s %s\n", b,c); } while(0)
103 #define msg4(a,b,c,d) do { fprintf(stderr,"%s %s %s\n", b,c,d); } while(0)
106 /* Debugging macros */
109 #define DEBUG( a ) printf( a )
110 #define DEBUG2( a,b ) printf( a,b )
111 #define DEBUG3( a,b,c ) printf( a,b,c )
114 #define DEBUG2( a,b )
115 #define DEBUG3( a,b,c )
117 #ifndef PACKAGE_VERSION
118 #define PACKAGE_VERSION ""
121 * The highest value a variable of type off_t can reach.
123 /* This is starting to get ugly. If someone knows a better way to find
124 * the maximum value of a signed type *without* relying on overflow
125 * (doing so breaks on 64bit architectures), that would be nice.
127 #define OFFT_MAX (((((off_t)1)<<((sizeof(off_t)-1)*8))-1)<<7)+127
128 #define LINELEN 256 /**< Size of static buffer used to read the
129 authorization file (yuck) */
130 #define BUFSIZE (1024*1024) /**< Size of buffer that can hold requests */
131 #define GIGA (1*1024*1024*1024) /**< 1 Gigabyte. Used as hunksize when doing
132 the multiple file thingy */
133 #define DIFFPAGESIZE 4096 /**< diff file uses those chunks */
134 #define F_READONLY 1 /**< flag to tell us a file is readonly */
135 #define F_MULTIFILE 2 /**< flag to tell us a file is exported using -m */
136 #define F_COPYONWRITE 4 /**< flag to tell us a file is exported using copyonwrite */
137 char difffilename[1024]; /**< filename of the copy-on-write file. Doesn't belong here! */
138 unsigned int timeout = 0; /**< disconnect timeout */
139 int autoreadonly = 0; /**< 1 = switch to readonly if opening readwrite isn't
141 char *auth_file="nbd_server.allow"; /**< authorization file */
142 char exportname2[1024]; /**< File I'm exporting, with virtualhost resolved */
143 off_t lastpoint = (off_t)-1; /**< keep track of where we are in the file, to
144 avoid an lseek if possible */
145 char pagebuf[DIFFPAGESIZE]; /**< when doing copyonwrite, this is
146 used as a temporary buffer to store
147 the exported block in. @todo this is
148 a great example of namespace
149 pollution. Throw it out. */
150 unsigned int port; /**< Port I'm listening at */
151 char *exportname; /**< File I'm exporting */
152 off_t exportsize = OFFT_MAX; /**< length of file I'm exporting */
153 off_t hunksize = OFFT_MAX; /**< size of each exported file in case of -m */
154 int flags = 0; /**< flags associated with this exported file */
155 int export[1024];/**< array of filedescriptors of exported files; only first is
156 used unless -m option is activated */
157 int difffile=-1; /**< filedescriptor for copyonwrite file */
158 u32 difffilelen=0 ; /**< number of pages in difffile */
159 u32 *difmap=NULL ; /**< Determine whether a block is in the original file
160 (difmap[block]==-1) or in the copyonwrite file (in which
161 case it contains the offset where it is to be found in the
162 copyonwrite file). @todo the kernel knows about sparse
163 files, we should use those instead. Should also be off_t
164 instead of u32; copyonwrite is probably broken wrt LFS */
165 char clientname[256] ;
166 int child_arraysize=DEFAULT_CHILD_ARRAY; /**< number of available slots for
168 pid_t *children; /**< child array */
169 char pidfname[256]; /**< name of our PID file */
172 * Variables associated with a copyonwrite server. Not yet used.
175 char* difffilename; /**< filename of the copy-on-write file */
176 int difffile; /**< filedescriptor of copyonwrite file. @todo
177 shouldn't this be an array too? (cfr
178 nbd_server_opts::export) Or make -m and -c
179 mutually exclusive */
180 u32 difffilelen; /**< number of pages in difffile */
181 u32 *difmap; /**< see comment on the global difmap for this one */
185 * Variables associated with a server. Not yet used. @todo modify the code to
186 * use an instance of this struct instead of the heap of global variables.
189 char* exportname; /**< filename of the file we're exporting */
190 unsigned int port; /**< port we're exporting this file at */
191 char* authname; /**< filename of the authorization file */
192 off_t exportsize; /**< size of the file we're exporting */
193 off_t hunksize; /**< size of a hunk of an exported file */
194 int flags; /**< flags associated with this exported file */
195 char* clientname; /**< peer */
196 unsigned int timeout;/**< how long a connection may be idle
198 int export[1024]; /**< array of filedescriptors of exported files;
199 only the first is actually used unless we're
200 doing the multiple file option */
201 cow_opts* cow; /**< only used if (flags | F_COPYONWRITE) (NULL
206 * Check whether a client is allowed to connect. Works with an authorization
207 * file which contains one line per machine, no wildcards.
209 * @param name IP address of client trying to connect (in human-readable form)
210 * @return 0 - authorization refused, 1 - OK
212 int authorized_client(char *name)
218 if ((f=fopen(auth_file,"r"))==NULL) {
219 msg4(LOG_INFO,"Can't open authorization file %s (%s).",
220 auth_file,strerror(errno)) ;
224 while (fgets(line,LINELEN,f)!=NULL) {
225 if (strncmp(line,name,strlen(name))==0) {
235 * Read data from a file descriptor into a buffer
237 * @param f a file descriptor
238 * @param buf a buffer
239 * @param len the number of bytes to be read
241 inline void readit(int f, void *buf, size_t len)
246 if ((res = read(f, buf, len)) <= 0)
247 err("Read failed: %m");
254 * Write data from a buffer into a filedescriptor
256 * @param f a file descriptor
257 * @param buf a buffer containing data
258 * @param len the number of bytes to be written
260 inline void writeit(int f, void *buf, size_t len)
265 if ((res = write(f, buf, len)) <= 0)
266 err("Send failed: %m");
273 * Parse the command line.
275 * @todo getopt() is a great thing, and easy to use. Also, we want to
276 * create a configuration file which nbd-server will read. Maybe do (as in,
279 * @param argc the argc argument to main()
280 * @param argv the argv argument to main()
282 void cmdline(int argc, char *argv[])
287 printf("This is nbd-server version " VERSION "\n");
288 printf("Usage: port file_to_export [size][kKmM] [-r] [-m] [-c] [-a timeout_sec]\n"
290 " -m multiple file\n"
291 " -c copy on write\n"
292 " -l file with list of hosts that are allowed to connect.\n"
293 " -a maximum idle seconds, terminates when idle time exceeded\n"
294 " if port is set to 0, stdin is used (for running from inetd)\n"
295 " if file_to_export contains '%%s', it is substituted with IP\n"
296 " address of machine trying to connect\n" );
299 port = atoi(argv[1]);
300 for (i = 3; i < argc; i++) {
301 if (*argv[i] == '-') {
302 switch (argv[i][1]) {
307 flags |= F_MULTIFILE;
310 case 'c': flags |=F_COPYONWRITE;
317 fprintf(stderr, "host list file requires an argument");
322 timeout = atoi(argv[i+1]);
325 fprintf(stderr, "timeout requires argument\n");
331 size_t last = strlen(argv[i])-1;
332 char suffix = argv[i][last];
333 if (suffix == 'k' || suffix == 'K' ||
334 suffix == 'm' || suffix == 'M')
335 argv[i][last] = '\0';
336 es = (off_t)atol(argv[i]);
348 exportname = argv[2];
352 * Signal handler for SIGCHLD
353 * @param s the signal we're handling (must be SIGCHLD, or something
356 void sigchld_handler(int s)
363 while((pid=wait(status)) > 0) {
364 if(WIFEXITED(status)) {
365 memset(buf,'\0', 80);
366 snprintf(buf, 79, "%d", WEXITSTATUS(status));
367 msg3(LOG_INFO, "Child exited with ", buf);
369 for(i=0;children[i]!=pid&&i<child_arraysize;i++);
370 if(i>=child_arraysize) {
371 memset(buf, '\0', 80);
372 snprintf(buf, 79, "%ld", (long)pid);
373 msg3(LOG_INFO, "SIGCHLD received for an unknown child with PID ", buf);
375 children[i]=(pid_t)0;
376 DEBUG2("Removing %d from the list of children", pid);
382 * Handle SIGTERM and dispatch it to our children
383 * @param s the signal we're handling (must be SIGTERM, or something
384 * is severely wrong).
386 void sigterm_handler(int s) {
390 for(i=0;i<child_arraysize;i++) {
392 kill(children[i], s);
405 * Detect the size of a file.
407 * @param export An open filedescriptor
408 * @return the size of the file, or OFFT_MAX if detection was
411 off_t size_autodetect(int export)
415 struct stat stat_buf;
418 #ifdef HAVE_SYS_MOUNT_H
419 #ifdef HAVE_SYS_IOCTL_H
421 DEBUG("looking for export size with ioctl BLKGETSIZE\n");
422 if (!ioctl(export, BLKGETSIZE, &es32) && es32) {
423 es = (off_t)es32 * (off_t)512;
426 #endif /* BLKGETSIZE */
427 #endif /* HAVE_SYS_IOCTL_H */
428 #endif /* HAVE_SYS_MOUNT_H */
430 DEBUG("looking for export size with fstat\n");
431 stat_buf.st_size = 0;
432 error = fstat(export, &stat_buf);
433 if (!error && stat_buf.st_size > 0) {
434 return (off_t)stat_buf.st_size;
436 err("fstat failed: %m");
439 DEBUG("looking for export size with lseek SEEK_END\n");
440 es = lseek(export, (off_t)0, SEEK_END);
441 if (es > ((off_t)0)) {
444 DEBUG2("lseek failed: %d", errno==EBADF?1:(errno==ESPIPE?2:(errno==EINVAL?3:4)));
447 err("Could not find size of exported block device: %m");
452 * Seek to a position in a file, unless we're already there.
453 * @param handle a filedescriptor
454 * @param a position to seek to
456 void maybeseek(int handle, off_t a) {
457 if (a < 0 || a > exportsize) {
458 err("Can not happen\n");
460 if (lastpoint != a) {
461 if (lseek(handle, a, SEEK_SET) < 0) {
462 err("Can not seek locally!\n");
471 * Write an amount of bytes at a given offset to the right file. This
472 * abstracts the write-side of the multiple file option.
474 * @param a The offset where the write should start
475 * @param buf The buffer to write from
476 * @param len The length of buf
477 * @return The number of bytes actually written, or -1 in case of an error
479 int rawexpwrite(off_t a, char *buf, size_t len)
483 maybeseek(export[a/hunksize], a%hunksize);
484 res = write(export[a/hunksize], buf, len);
485 return (res < 0 || (size_t)res != len);
489 * seek to a position in a file, no matter what. Used when using maybeseek is a
490 * bad idea (for instance, because we're reading the copyonwrite file instead
491 * of the exported file).
492 * @param handle a filedescriptor
493 * @param a position to seek to
494 * @todo get rid of this; lastpoint is a global variable right now, but it
495 * shouldn't be. If we pass it on as a parameter, that makes things a *lot*
498 void myseek(int handle,off_t a) {
499 if (lseek(handle, a, SEEK_SET) < 0) {
500 err("Can not seek locally!\n");
505 * Read an amount of bytes at a given offset from the right file. This
506 * abstracts the read-side of the multiple files option.
508 * @param a The offset where the read should start
509 * @param buf A buffer to read into
510 * @param len The size of buf
511 * @return The number of bytes actually read, or -1 in case of an
514 int rawexpread(off_t a, char *buf, size_t len)
518 maybeseek(export[a/hunksize], a%hunksize);
519 res = read(export[a/hunksize], buf, len);
520 return (res < 0 || (size_t)res != len);
524 * Read an amount of bytes at a given offset from the right file. This
525 * abstracts the read-side of the copyonwrite stuff, and calls
526 * rawexpread() with the right parameters to do the actual work.
527 * @param a The offset where the read should start
528 * @param buf A buffer to read into
529 * @param len The size of buf
530 * @return The number of bytes actually read, or -1 in case of an error
532 int expread(off_t a, char *buf, size_t len)
535 off_t mapcnt, mapl, maph, pagestart;
537 if (!(flags & F_COPYONWRITE))
538 return rawexpread(a, buf, len);
539 DEBUG3("Asked to read %d bytes at %Lu.\n", len, (unsigned long long)a);
541 mapl=a/DIFFPAGESIZE; maph=(a+len-1)/DIFFPAGESIZE;
543 for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
544 pagestart=mapcnt*DIFFPAGESIZE;
546 rdlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
547 len : (size_t)DIFFPAGESIZE-offset;
548 if (difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
549 DEBUG3("Page %Lu is at %lu\n", (unsigned long long)mapcnt,
550 (unsigned long)difmap[mapcnt]);
551 myseek(difffile, difmap[mapcnt]*DIFFPAGESIZE+offset);
552 if (read(difffile, buf, rdlen) != rdlen) return -1;
553 } else { /* the block is not there */
554 DEBUG2("Page %Lu is not here, we read the original one\n",
555 (unsigned long long)mapcnt);
556 return rawexpread(a, buf, rdlen);
558 len-=rdlen; a+=rdlen; buf+=rdlen;
564 * Write an amount of bytes at a given offset to the right file. This
565 * abstracts the write-side of the copyonwrite option, and calls
566 * rawexpwrite() with the right parameters to do the actual work.
568 * @param a The offset where the write should start
569 * @param buf The buffer to write from
570 * @param len The length of buf
571 * @return The number of bytes actually written, or -1 in case of an error
573 int expwrite(off_t a, char *buf, size_t len)
575 off_t mapcnt,mapl,maph ;
580 if (!(flags & F_COPYONWRITE))
581 return(rawexpwrite(a,buf,len));
582 DEBUG3("Asked to write %d bytes at %Lu.\n", len, (unsigned long long)a);
584 mapl=a/DIFFPAGESIZE ; maph=(a+len-1)/DIFFPAGESIZE ;
586 for (mapcnt=mapl;mapcnt<=maph;mapcnt++) {
587 pagestart=mapcnt*DIFFPAGESIZE ;
589 wrlen=(0<DIFFPAGESIZE-offset && len<(size_t)(DIFFPAGESIZE-offset)) ?
590 len : (size_t)DIFFPAGESIZE-offset;
592 if (difmap[mapcnt]!=(u32)(-1)) { /* the block is already there */
593 DEBUG3("Page %Lu is at %lu\n", (unsigned long long)mapcnt,
594 (unsigned long)difmap[mapcnt]) ;
595 myseek(difffile,difmap[mapcnt]*DIFFPAGESIZE+offset) ;
596 if (write(difffile, buf, wrlen) != wrlen) return -1 ;
597 } else { /* the block is not there */
598 myseek(difffile,difffilelen*DIFFPAGESIZE) ;
599 difmap[mapcnt]=difffilelen++ ;
600 DEBUG3("Page %Lu is not here, we put it at %lu\n",
601 (unsigned long long)mapcnt,
602 (unsigned long)difmap[mapcnt]);
604 if (rdlen+pagestart%hunksize>hunksize)
605 rdlen=hunksize-(pagestart%hunksize) ;
606 if (rawexpread(pagestart,pagebuf,rdlen)) return -1 ;
607 memcpy(pagebuf+offset,buf,wrlen) ;
608 if (write(difffile,pagebuf,DIFFPAGESIZE)!=DIFFPAGESIZE) return -1 ;
610 len-=wrlen ; a+=wrlen ; buf+=wrlen ;
616 * Do the initial negotiation.
618 * @param net A socket to do the negotiation over
620 void negotiate(int net) {
624 memset(zeros, 0, 290);
625 if (write(net, INIT_PASSWD, 8) < 0)
626 err("Negotiation failed: %m");
627 cliserv_magic = htonll(cliserv_magic);
628 if (write(net, &cliserv_magic, sizeof(cliserv_magic)) < 0)
629 err("Negotiation failed: %m");
630 size_host = htonll((u64)exportsize);
631 if (write(net, &size_host, 8) < 0)
632 err("Negotiation failed: %m");
633 if (write(net, zeros, 128) < 0)
634 err("Negotiation failed: %m");
637 /** sending macro; not really required. Uses variables in the local
638 * scope of mainloop(). Get rid of it. */
639 #define SEND writeit( net, &reply, sizeof( reply ));
640 /** error macro; not sure whether we really need this. Uses variables
641 * in the local scope of mainloop(). Get rid of this beast. */
642 #define ERROR { reply.error = htonl(-1); SEND; reply.error = 0; lastpoint = -1; }
644 * Serve a file to a single client.
646 * @todo This beast needs to be split up in many tiny little manageable
647 * pieces. Preferably with a chainsaw.
649 * @param net A network socket, connected to an nbd client
652 int mainloop(int net)
654 struct nbd_request request;
655 struct nbd_reply reply;
660 DEBUG("Entering request loop!\n");
661 reply.magic = htonl(NBD_REPLY_MAGIC);
672 readit(net, &request, sizeof(request));
673 request.from = ntohll(request.from);
674 request.type = ntohl(request.type);
676 if (request.type==NBD_CMD_DISC) { /* Disconnect request */
677 if (difmap) free(difmap) ;
679 close(difffile) ; unlink(difffilename) ; }
680 err("Disconnect request received.") ;
683 len = ntohl(request.len);
685 if (request.magic != htonl(NBD_REQUEST_MAGIC))
686 err("Not enough magic.");
688 err("Request too big!");
690 printf("%s from %Lu (%Lu) len %d, ", request.type ? "WRITE" :
691 "READ", (unsigned long long)request.from,
692 (unsigned long long)request.from / 512, len);
694 memcpy(reply.handle, request.handle, sizeof(reply.handle));
695 if ((request.from + len) > (OFFT_MAX)) {
696 DEBUG("[Number too large!]");
701 if (((ssize_t)((off_t)request.from + len) > exportsize) ||
702 ((flags & F_READONLY) && request.type)) {
708 if (request.type==1) { /* WRITE */
709 DEBUG("wr: net->buf, ");
710 readit(net, buf, len);
712 if ((autoreadonly == 1) || expwrite(request.from, buf, len)) {
713 DEBUG("Write failed: %m" );
725 if (expread(request.from, buf + sizeof(struct nbd_reply), len)) {
727 DEBUG("Read failed: %m");
734 memcpy(buf, &reply, sizeof(struct nbd_reply));
735 writeit(net, buf, len + sizeof(struct nbd_reply));
741 * Split a single exportfile into multiple ones, if that was asked.
742 * @return 0 on success, -1 on failure
744 int splitexport(void) {
747 for (i=0; i<exportsize; i+=hunksize) {
748 char exportname3[1024];
750 if(flags & F_MULTIFILE) {
751 snprintf(exportname3, 1024, "%s.%d", exportname2, (int)(i/hunksize));
753 strncpy(exportname3, exportname2, 1024);
755 exportname3[1023]='\0';
756 printf( "Opening %s\n", exportname3 );
757 if ((export[i/hunksize] = open(exportname3, (flags & F_READONLY) ? O_RDONLY : O_RDWR)) == -1) {
758 /* Read WRITE ACCESS was requested by media is only read only */
761 if ((export[i/hunksize] = open(exportname3, O_RDONLY)) == -1)
762 err("Could not open exported file: %m");
766 if (flags & F_COPYONWRITE) {
767 snprintf(difffilename, 1024, "%s-%s-%d.diff",exportname2,clientname,
769 difffilename[1023]='\0';
770 msg3(LOG_INFO,"About to create map and diff file %s",difffilename) ;
771 difffile=open(difffilename,O_RDWR | O_CREAT | O_TRUNC,0600) ;
772 if (difffile<0) err("Could not create diff file (%m)") ;
773 if ((difmap=calloc(exportsize/DIFFPAGESIZE,sizeof(u32)))==NULL)
774 err("Could not allocate memory") ;
775 for (i=0;i<exportsize/DIFFPAGESIZE;i++) difmap[i]=(u32)-1 ;
782 * Serve a connection.
784 * @todo allow for multithreading, perhaps use libevent.
786 * @param net A network socket connected to an nbd client
788 void serveconnection(int net) {
791 if (exportsize == OFFT_MAX) {
792 exportsize = size_autodetect(export[0]);
794 if (exportsize > OFFT_MAX) {
795 err("Size of exported file is too big\n");
798 memset(buf, '\0', 80);
799 snprintf(buf, 79, "%Lu", (unsigned long long)exportsize);
800 msg3(LOG_INFO, "size of exported file/device is ", buf);
809 * Find the name of the file we have to serve. This will use snprintf()
810 * to put the IP address of the client inside a filename containing
811 * "%s". That name is then written to exportname2
813 * @param net A socket connected to an nbd client
814 * @param clientname a buffer which must be at least 255+1 bytes long;
815 * the IP address (in human-readable format) will be copied in there.
817 void set_peername(int net,char *clientname)
819 struct sockaddr_in addrin;
820 int addrinlen = sizeof( addrin );
823 if (getpeername( net, (struct sockaddr *) &addrin, &addrinlen ) < 0)
824 err("getsockname failed: %m");
825 peername = inet_ntoa(addrin.sin_addr);
826 snprintf(exportname2, 1024, exportname, peername);
827 exportname2[1023]='\0';
829 msg4(LOG_INFO, "connect from %s, assigned file is %s",
830 peername, exportname2);
831 strncpy(clientname,peername,255) ;
835 * Connect the socket, and start to serve. This function will fork()
836 * if a connection from an authorized client is received, and will
839 * @todo modularize this giant beast. Preferably with a chainsaw. Also,
840 * it has no business starting mainloop(); it should connect, and be
843 * @param port the port where we will listen
845 void connectme(unsigned int port)
847 struct sockaddr_in addrin;
849 int addrinlen = sizeof(addrin);
850 int net, sock, newpid, i;
864 snprintf(pidfname, sizeof(char)*255, "/var/run/nbd-server.%d.pid", port);
865 pidf=fopen(pidfname, "w");
867 fprintf(pidf,"%d", (int)getpid());
871 fprintf(stderr, "Not fatal; continuing");
875 #endif /* NODAEMON */
877 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
880 /* lose the pesky "Address already in use" error message */
881 if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
882 err("setsockopt SO_REUSEADDR");
884 if (setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,&yes,sizeof(int)) == -1) {
885 err("setsockopt SO_KEEPALIVE");
888 DEBUG("Waiting for connections... bind, ");
889 addrin.sin_family = AF_INET;
890 addrin.sin_port = htons(port);
891 addrin.sin_addr.s_addr = 0;
892 if (bind(sock, (struct sockaddr *) &addrin, addrinlen) < 0)
895 if (listen(sock, 1) < 0)
898 sa.sa_handler = sigchld_handler;
899 sigemptyset(&sa.sa_mask);
900 sa.sa_flags = SA_RESTART;
901 if(sigaction(SIGCHLD, &sa, NULL) == -1)
902 err("sigaction: %m");
903 sa.sa_handler = sigterm_handler;
904 sigemptyset(&sa.sa_mask);
905 sa.sa_flags = SA_RESTART;
906 if(sigaction(SIGTERM, &sa, NULL) == -1)
907 err("sigaction: %m");
908 children=malloc(sizeof(pid_t)*child_arraysize);
909 memset(children, 0, sizeof(pid_t)*DEFAULT_CHILD_ARRAY);
910 for(;;) { /* infinite loop */
911 if ((net = accept(sock, (struct sockaddr *) &addrin, &addrinlen)) < 0)
914 set_peername(net,clientname);
915 if (!authorized_client(clientname)) {
916 msg2(LOG_INFO,"Unauthorized client") ;
920 msg2(LOG_INFO,"Authorized client") ;
921 for(i=0;children[i]&&i<child_arraysize;i++);
922 if(i>=child_arraysize) {
925 ptr=realloc(children, sizeof(pid_t)*child_arraysize);
928 memset(children+child_arraysize, 0, sizeof(pid_t)*DEFAULT_CHILD_ARRAY);
930 child_arraysize+=DEFAULT_CHILD_ARRAY;
932 msg2(LOG_INFO,"Not enough memory to store child PID");
938 if ((children[i]=fork())<0) {
939 msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ;
943 if (children[i]>0) { /* parent */
944 close(net) ; continue ; }
950 msg2(LOG_INFO,"Starting to serve") ;
951 serveconnection(net) ;
956 * Main entry point...
958 int main(int argc, char *argv[])
960 if (sizeof( struct nbd_request )!=28) {
961 fprintf(stderr,"Bad size of structure. Alignment problems?\n");
967 if (!port) return 1 ;
968 connectme(port); /* serve infinitely */