* <wouter@debian.org>
*/
+/* Includes LFS defines, which defines behaviours of some of the following
+ * headers, so must come before those */
+#include "config.h"
+#include "lfs.h"
+
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/wait.h> /* wait */
+#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
+#endif
#include <sys/param.h>
+#ifdef HAVE_SYS_MOUNT_H
#include <sys/mount.h> /* For BLKGETSIZE */
+#endif
#include <signal.h> /* sigaction */
#include <netinet/tcp.h>
#include <netinet/in.h> /* sockaddr_in, htons, in_addr */
#include <strings.h>
#include <dirent.h>
+#include <glib.h>
+
/* used in cliserv.h, so must come first */
#define MY_NAME "nbd_server"
#include "cliserv.h"
/** Logging macros, now nothing goes to syslog unless you say ISSERVER */
#ifdef ISSERVER
-#define msg2(a,b) syslog(a,b)
-#define msg3(a,b,c) syslog(a,b,c)
-#define msg4(a,b,c,d) syslog(a,b,c,d)
+#define msg2(a,b) syslog(a,"%s", b)
+#define msg3(a,b,c) syslog(a,"%s %s", b,c)
+#define msg4(a,b,c,d) syslog(a,"%s %s %s", b,c,d)
#else
-#define msg2(a,b) do { fprintf(stderr,b) ; fputs("\n",stderr) ; } while(0)
-#define msg3(a,b,c) do { fprintf(stderr,b,c); fputs("\n",stderr) ; } while(0)
-#define msg4(a,b,c,d) do { fprintf(stderr,b,c,d); fputs("\n",stderr) ; } while(0)
+#define msg2(a,b) do { fprintf(stderr,"%s\n", b) ; } while(0)
+#define msg3(a,b,c) do { fprintf(stderr,"%s %s\n", b,c); } while(0)
+#define msg4(a,b,c,d) do { fprintf(stderr,"%s %s %s\n", b,c,d); } while(0)
#endif
/* Debugging macros */
#define DEBUG2( a,b )
#define DEBUG3( a,b,c )
#endif
-/** sending macro... not really required */
-#define SEND writeit( net, &reply, sizeof( reply ));
-/** error macro... not sure whether we really need this */
-#define ERROR { reply.error = htonl(-1); SEND; reply.error = 0; lastpoint = -1; }
#ifndef PACKAGE_VERSION
#define PACKAGE_VERSION ""
#endif
#define F_READONLY 1 /**< flag to tell us a file is readonly */
#define F_MULTIFILE 2 /**< flag to tell us a file is exported using -m */
#define F_COPYONWRITE 4 /**< flag to tell us a file is exported using copyonwrite */
-char difffilename[256]; /**< filename of the copy-on-write file. Doesn't belong here! */
+char difffilename[1024]; /**< filename of the copy-on-write file. Doesn't belong here! */
unsigned int timeout = 0; /**< disconnect timeout */
int autoreadonly = 0; /**< 1 = switch to readonly if opening readwrite isn't
possible */
/**
* Variables associated with a copyonwrite server. Not yet used.
**/
-typedef struct __cow_opts {
+typedef struct {
char* difffilename; /**< filename of the copy-on-write file */
int difffile; /**< filedescriptor of copyonwrite file. @todo
shouldn't this be an array too? (cfr
} cow_opts;
/**
- * Variables associated with a server. Not yet used.
+ * Variables associated with a server. Not yet used. @todo modify the code to
+ * use an instance of this struct instead of the heap of global variables.
**/
-typedef struct __nbd_server_opts {
+typedef struct {
char* exportname; /**< filename of the file we're exporting */
unsigned int port; /**< port we're exporting this file at */
char* authname; /**< filename of the authorization file */
int export[1024]; /**< array of filedescriptors of exported files;
only the first is actually used unless we're
doing the multiple file option */
- cow_opts* cow; /**< only used if (flags | F_COPYONWRITE) */
+ cow_opts* cow; /**< only used if (flags | F_COPYONWRITE) (NULL
+ otherwise) */
} nbd_server_opts;
/**
- * Check whether a client is allowed to connect. Works with an
- * authorization file which contains one line per machine, no
- * wildcards.
+ * Check whether a client is allowed to connect. Works with an authorization
+ * file which contains one line per machine, no wildcards.
+ *
* @param name IP address of client trying to connect (in human-readable form)
* @return 0 - authorization refused, 1 - OK
**/
* Parse the command line.
*
* @todo getopt() is a great thing, and easy to use. Also, we want to
- * create a configuration file which nbd-server will read.
+ * create a configuration file which nbd-server will read. Maybe do (as in,
+ * parse) that here.
*
* @param argc the argc argument to main()
* @param argv the argv argument to main()
{
int* status=NULL;
int i;
+ char buf[80];
pid_t pid;
while((pid=wait(status)) > 0) {
if(WIFEXITED(status)) {
- msg3(LOG_INFO, "Child exited with %d", WEXITSTATUS(status));
+ memset(buf,'\0', 80);
+ snprintf(buf, 79, "%d", WEXITSTATUS(status));
+ msg3(LOG_INFO, "Child exited with ", buf);
}
for(i=0;children[i]!=pid&&i<child_arraysize;i++);
if(i>=child_arraysize) {
- msg3(LOG_INFO, "SIGCHLD received for an unknown child with PID %ld",(long) pid);
+ memset(buf, '\0', 80);
+ snprintf(buf, 79, "%ld", (long)pid);
+ msg3(LOG_INFO, "SIGCHLD received for an unknown child with PID ", buf);
} else {
children[i]=(pid_t)0;
DEBUG2("Removing %d from the list of children", pid);
if(parent) {
unlink(pidfname);
}
-
+
exit(0);
}
u32 es32;
struct stat stat_buf;
int error;
-
- DEBUG("looking for export size with lseek SEEK_END\n");
- es = lseek(export, (off_t)0, SEEK_END);
- if (es > ((off_t)0)) {
+
+#ifdef HAVE_SYS_MOUNT_H
+#ifdef HAVE_SYS_IOCTL_H
+#ifdef BLKGETSIZE
+ DEBUG("looking for export size with ioctl BLKGETSIZE\n");
+ if (!ioctl(export, BLKGETSIZE, &es32) && es32) {
+ es = (off_t)es32 * (off_t)512;
return es;
- } else {
- DEBUG2("lseek failed: %d", errno==EBADF?1:(errno==ESPIPE?2:(errno==EINVAL?3:4)));
- }
-
+ }
+#endif /* BLKGETSIZE */
+#endif /* HAVE_SYS_IOCTL_H */
+#endif /* HAVE_SYS_MOUNT_H */
+
DEBUG("looking for export size with fstat\n");
stat_buf.st_size = 0;
error = fstat(export, &stat_buf);
} else {
err("fstat failed: %m");
}
-
-#ifdef BLKGETSIZE
- DEBUG("looking for export size with ioctl BLKGETSIZE\n");
- if (!ioctl(export, BLKGETSIZE, &es32) && es32) {
- es = (off_t)es32 * (off_t)512;
+
+ DEBUG("looking for export size with lseek SEEK_END\n");
+ es = lseek(export, (off_t)0, SEEK_END);
+ if (es > ((off_t)0)) {
return es;
- }
-#endif
+ } else {
+ DEBUG2("lseek failed: %d", errno==EBADF?1:(errno==ESPIPE?2:(errno==EINVAL?3:4)));
+ }
+
err("Could not find size of exported block device: %m");
return OFFT_MAX;
}
/**
* seek to a position in a file, no matter what. Used when using maybeseek is a
* bad idea (for instance, because we're reading the copyonwrite file instead
- * of the exported file)
+ * of the exported file).
* @param handle a filedescriptor
* @param a position to seek to
+ * @todo get rid of this; lastpoint is a global variable right now, but it
+ * shouldn't be. If we pass it on as a parameter, that makes things a *lot*
+ * easier.
**/
void myseek(int handle,off_t a) {
if (lseek(handle, a, SEEK_SET) < 0) {
err("Negotiation failed: %m");
}
+/** sending macro; not really required. Uses variables in the local
+ * scope of mainloop(). Get rid of it. */
+#define SEND writeit( net, &reply, sizeof( reply ));
+/** error macro; not sure whether we really need this. Uses variables
+ * in the local scope of mainloop(). Get rid of this beast. */
+#define ERROR { reply.error = htonl(-1); SEND; reply.error = 0; lastpoint = -1; }
/**
* Serve a file to a single client.
*
**/
int splitexport(void) {
off_t i ;
-
+
for (i=0; i<exportsize; i+=hunksize) {
char exportname3[1024];
-
- sprintf(exportname3, exportname2, i/hunksize);
+
+ if(flags & F_MULTIFILE) {
+ snprintf(exportname3, 1024, "%s.%d", exportname2, (int)(i/hunksize));
+ } else {
+ strncpy(exportname3, exportname2, 1024);
+ }
+ exportname3[1023]='\0';
printf( "Opening %s\n", exportname3 );
if ((export[i/hunksize] = open(exportname3, (flags & F_READONLY) ? O_RDONLY : O_RDWR)) == -1) {
/* Read WRITE ACCESS was requested by media is only read only */
}
if (flags & F_COPYONWRITE) {
- sprintf(difffilename,"%s-%s-%d.diff",exportname2,clientname,
+ snprintf(difffilename, 1024, "%s-%s-%d.diff",exportname2,clientname,
(int)getpid()) ;
+ difffilename[1023]='\0';
msg3(LOG_INFO,"About to create map and diff file %s",difffilename) ;
difffile=open(difffilename,O_RDWR | O_CREAT | O_TRUNC,0600) ;
if (difffile<0) err("Could not create diff file (%m)") ;
*
* @param net A network socket connected to an nbd client
**/
-void serveconnection(int net) {
+void serveconnection(int net) {
+ char buf[80];
splitexport();
if (exportsize == OFFT_MAX) {
exportsize = size_autodetect(export[0]);
if (exportsize > OFFT_MAX) {
err("Size of exported file is too big\n");
}
- else
- msg3(LOG_INFO, "size of exported file/device is %Lu",
- (unsigned long long)exportsize);
+ else {
+ memset(buf, '\0', 80);
+ snprintf(buf, 79, "%Lu", (unsigned long long)exportsize);
+ msg3(LOG_INFO, "size of exported file/device is ", buf);
+ }
setmysockopt(net);
}
/**
- * Find the name of the file we have to serve. This will use sprintf()
+ * Find the name of the file we have to serve. This will use snprintf()
* to put the IP address of the client inside a filename containing
* "%s". That name is then written to exportname2
*
if (getpeername( net, (struct sockaddr *) &addrin, &addrinlen ) < 0)
err("getsockname failed: %m");
peername = inet_ntoa(addrin.sin_addr);
- sprintf(exportname2, exportname, peername);
+ snprintf(exportname2, 1024, exportname, peername);
+ exportname2[1023]='\0';
msg4(LOG_INFO, "connect from %s, assigned file is %s",
peername, exportname2);