summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2013-08-01 18:14:15 +0200
committerSimon Rettberg2013-08-01 18:14:15 +0200
commit96b3a0feb963466447ca8dbc571bc5f670d533cc (patch)
treee546179f4d6d5cbb23dae202a8bf59b9f2ce95bb
parent[SERVER] Add inih (http://code.google.com/p/inih/) for *.ini parsing (diff)
downloaddnbd3-96b3a0feb963466447ca8dbc571bc5f670d533cc.tar.gz
dnbd3-96b3a0feb963466447ca8dbc571bc5f670d533cc.tar.xz
dnbd3-96b3a0feb963466447ca8dbc571bc5f670d533cc.zip
[SERVER] Add command line options to create empty image of certain size with empty cache map (so it needs an uplink server)
-rw-r--r--src/server/altservers.c48
-rw-r--r--src/server/altservers.h4
-rw-r--r--src/server/globals.c29
-rw-r--r--src/server/globals.h9
-rw-r--r--src/server/helper.c189
-rw-r--r--src/server/helper.h4
-rw-r--r--src/server/image.c143
-rw-r--r--src/server/image.h3
-rw-r--r--src/server/memlog.c75
-rw-r--r--src/server/server.c70
10 files changed, 383 insertions, 191 deletions
diff --git a/src/server/altservers.c b/src/server/altservers.c
index 6301c32..44061a3 100644
--- a/src/server/altservers.c
+++ b/src/server/altservers.c
@@ -4,6 +4,7 @@
#include "sockhelper.h"
#include "memlog.h"
#include "helper.h"
+#include "globals.h"
#include <stdlib.h>
#include <unistd.h>
#include <sys/epoll.h>
@@ -12,6 +13,7 @@
#include <assert.h>
#include <inttypes.h>
#include <time.h>
+#include <stdio.h>
#include "../serialize.h"
static dnbd3_connection_t *pending[SERVER_MAX_PENDING_ALT_CHECKS];
@@ -36,6 +38,52 @@ void altserver_init()
}
}
+int altservers_load()
+{
+ int count = 0;
+ char *name = NULL, *space;
+ char line[1000];
+ dnbd3_host_t host;
+ asprintf( &name, "%s/%s", _configDir, "alt-servers" );
+ if ( name == NULL ) return -1;
+ FILE *fp = fopen( name, "r" );
+ free( name );
+ if ( fp == NULL ) return -1;
+ while ( !feof( fp ) ) {
+ if ( fgets( line, 1000, fp ) == NULL ) break;
+ trim_right( line );
+ space = strchr( line, ' ' );
+ if ( space != NULL ) *space++ = '\0';
+ if ( !parse_address( line, &host ) ) {
+ if ( space != NULL ) *--space = ' ';
+ memlogf( "[WARNING] Invalid entry in alt-servers file ignored: '%s'", line );
+ continue;
+ }
+ if ( altservers_add( &host, space ) ) ++count;
+ }
+ fclose( fp );
+ return count;
+}
+
+int altservers_add(dnbd3_host_t *host, const char *comment)
+{
+ int i, freeSlot = -1;
+ spin_lock( &_alts_lock );
+ for (i = 0; i < _num_alts; ++i) {
+ if ( is_same_server( &_alt_servers[i].host, host ) ) {
+ spin_unlock( &_alts_lock );
+ return FALSE;
+ } else if ( freeSlot == -1 && _alt_servers[i].host.type == 0 ) {
+ freeSlot = i;
+ }
+ }
+ if ( freeSlot == -1 ) freeSlot = _num_alts++;
+ _alt_servers[freeSlot].host = *host;
+ if ( comment != NULL ) snprintf( _alt_servers[freeSlot].comment, COMMENT_LENGTH, "%s", comment );
+ spin_unlock( &_alts_lock );
+ return TRUE;
+}
+
/**
* ONLY called from the passed uplink's main thread
*/
diff --git a/src/server/altservers.h b/src/server/altservers.h
index 6aec195..e080d13 100644
--- a/src/server/altservers.h
+++ b/src/server/altservers.h
@@ -5,6 +5,10 @@
void altserver_init();
+int altservers_load();
+
+int altservers_add(dnbd3_host_t *host, const char *comment);
+
void altserver_find_uplink(dnbd3_connection_t *uplink);
int altservers_get_matching(dnbd3_host_t *host, dnbd3_server_entry_t *output, int size);
diff --git a/src/server/globals.c b/src/server/globals.c
index bfc682b..d84e3f7 100644
--- a/src/server/globals.c
+++ b/src/server/globals.c
@@ -1,7 +1,36 @@
#include "globals.h"
+#include "ini.h"
+#include "memlog.h"
#include "../types.h"
#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+char *_configDir = NULL;
char *_basePath = NULL;
int _vmdkLegacyMode = FALSE;
int _shutdown = 0;
+
+#define SAVE_TO_VAR_STR(ss, kk) do { if (strcmp(section, #ss) == 0 && strcmp(key, #kk) == 0) { if (_ ## kk != NULL) free(_ ## kk); _ ## kk = strdup(value); } } while (0)
+#define SAVE_TO_VAR_BOOL(ss, kk) do { if (strcmp(section, #ss) == 0 && strcmp(key, #kk) == 0) _ ## kk = atoi(value) != 0 || strcmp(value, "true") == 0 || strcmp(value, "True") == 0 || strcmp(value, "TRUE") == 0; } while (0)
+#define SAVE_TO_VAR_INT(ss, kk) do { if (strcmp(section, #ss) == 0 && strcmp(key, #kk) == 0) _ ## kk = atoi(value); } while (0)
+
+static int ini_handler(void *custom, const char* section, const char* key, const char* value)
+{
+ SAVE_TO_VAR_STR( dnbd3, basePath );
+ SAVE_TO_VAR_BOOL( dnbd3, vmdkLegacyMode );
+ return TRUE;
+}
+
+void globals_loadConfig()
+{
+ char *name = NULL;
+ asprintf( &name, "%s/%s", _configDir, CONFIG_FILENAME );
+ if ( name == NULL ) return;
+ ini_parse( name, &ini_handler, NULL );
+ free( name );
+ if ( _basePath != NULL && _basePath[0] != '/' ) {
+ memlogf( "[ERROR] _basePath must be absolute!" );
+ exit( EXIT_FAILURE );
+ }
+}
diff --git a/src/server/globals.h b/src/server/globals.h
index d3424b6..2dd6e13 100644
--- a/src/server/globals.h
+++ b/src/server/globals.h
@@ -116,9 +116,14 @@ struct _dnbd3_client
};
// #######################################################
+#define CONFIG_FILENAME "server.conf"
+/**
+ * Base directory where the configuration files reside. Will never have a trailing slash.
+ */
+extern char *_configDir;
/**
- * Base directory where all images are stored in. Will always have a trailing slash
+ * Base directory where all images are stored in. Will never have a trailing slash.
*/
extern char *_basePath;
@@ -129,4 +134,6 @@ extern int _vmdkLegacyMode;
extern int _shutdown;
+void globals_loadConfig();
+
#endif /* GLOBALS_H_ */
diff --git a/src/server/helper.c b/src/server/helper.c
index dc83fb4..b028ad1 100644
--- a/src/server/helper.c
+++ b/src/server/helper.c
@@ -3,16 +3,19 @@
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
+#include <assert.h>
+#include <sys/stat.h>
#include "../types.h"
#include "../config.h"
/**
* Parse IPv4 or IPv6 address in string representation to a suitable format usable by the BSD socket library
* @string eg. "1.2.3.4" or "2a01::10:5", optially with port appended, eg "1.2.3.4:6666" or "[2a01::10:5]:6666"
- * @af will contain either AF_INET or AF_INET6
- * @addr will contain the address in network representation
- * @port will contain the port in network representation, defaulting to #define PORT if none was given
- * returns 1 on success, 0 in failure. contents of af, addr and port are undefined in the latter case
+ * @host pointer to dnbd3_host_t that will be filled with the following data:
+ * type will contain either AF_INET or AF_INET6
+ * addr will contain the address in network representation
+ * port will contain the port in network representation, defaulting to #define PORT if none was given
+ * returns TRUE on success, FALSE in failure. contents of af, addr and port are undefined in the latter case
* !! Contents of @string might be modified by this function !!
*/
char parse_address(char *string, dnbd3_host_t *host)
@@ -21,61 +24,52 @@ char parse_address(char *string, dnbd3_host_t *host)
struct in6_addr v6;
// Try IPv4 without port
- if (1 == inet_pton(AF_INET, string, &v4))
- {
+ if ( 1 == inet_pton( AF_INET, string, &v4 ) ) {
host->type = AF_INET;
- memcpy(host->addr, &v4, 4);
- host->port = htons(PORT);
- return 1;
+ memcpy( host->addr, &v4, 4 );
+ host->port = htons( PORT );
+ return TRUE;
}
// Try IPv6 without port
- if (1 == inet_pton(AF_INET6, string, &v6))
- {
+ if ( 1 == inet_pton( AF_INET6, string, &v6 ) ) {
host->type = AF_INET6;
- memcpy(host->addr, &v6, 16);
- host->port = htons(PORT);
- return 1;
+ memcpy( host->addr, &v6, 16 );
+ host->port = htons( PORT );
+ return TRUE;
}
// Scan for port
char *portpos = NULL, *ptr = string;
- while (*ptr)
- {
- if (*ptr == ':')
- portpos = ptr;
+ while ( *ptr ) {
+ if ( *ptr == ':' ) portpos = ptr;
++ptr;
}
- if (portpos == NULL)
- return 0; // No port in string
+ if ( portpos == NULL ) return FALSE; // No port in string
// Consider IP being surrounded by [ ]
- if (*string == '[' && *(portpos - 1) == ']')
- {
+ if ( *string == '[' && *(portpos - 1) == ']' ) {
++string;
*(portpos - 1) = '\0';
}
*portpos++ = '\0';
- int p = atoi(portpos);
- if (p < 1 || p > 65535)
- return 0; // Invalid port
- host->port = htons((uint16_t)p);
+ int p = atoi( portpos );
+ if ( p < 1 || p > 65535 ) return FALSE; // Invalid port
+ host->port = htons( (uint16_t)p );
// Try IPv4 with port
- if (1 == inet_pton(AF_INET, string, &v4))
- {
+ if ( 1 == inet_pton( AF_INET, string, &v4 ) ) {
host->type = AF_INET;
- memcpy(host->addr, &v4, 4);
- return 1;
+ memcpy( host->addr, &v4, 4 );
+ return TRUE;
}
// Try IPv6 with port
- if (1 == inet_pton(AF_INET6, string, &v6))
- {
+ if ( 1 == inet_pton( AF_INET6, string, &v6 ) ) {
host->type = AF_INET6;
- memcpy(host->addr, &v6, 16);
- return 1;
+ memcpy( host->addr, &v6, 16 );
+ return TRUE;
}
// FAIL
- return 0;
+ return FALSE;
}
/**
@@ -86,110 +80,85 @@ char parse_address(char *string, dnbd3_host_t *host)
char host_to_string(const dnbd3_host_t *host, char *target, size_t targetlen)
{
// Worst case: Port 5 chars, ':' to separate ip and port 1 char, terminating null 1 char = 7, [] for IPv6
- if (targetlen < 10)
- return FALSE;
- if (host->type == AF_INET6)
- {
+ if ( targetlen < 10 ) return FALSE;
+ if ( host->type == AF_INET6 ) {
*target++ = '[';
- inet_ntop(AF_INET6, host->addr, target, targetlen - 9);
- target += strlen(target);
+ inet_ntop( AF_INET6, host->addr, target, targetlen - 9 );
+ target += strlen( target );
*target++ = ']';
- }
- else if (host->type == AF_INET)
- {
- inet_ntop(AF_INET, host->addr, target, targetlen - 7);
- target += strlen(target);
- }
- else
- {
- snprintf(target, targetlen, "<?addrtype=%d>", (int)host->type);
+ } else if ( host->type == AF_INET ) {
+ inet_ntop( AF_INET, host->addr, target, targetlen - 7 );
+ target += strlen( target );
+ } else {
+ snprintf( target, targetlen, "<?addrtype=%d>", (int)host->type );
return FALSE;
}
*target = '\0';
- if (host->port != 0)
- {
+ if ( host->port != 0 ) {
// There are still at least 7 bytes left in the buffer, port is at most 5 bytes + ':' + '\0' = 7
- snprintf(target, 7, ":%d", (int)ntohs(host->port));
+ snprintf( target, 7, ":%d", (int)ntohs( host->port ) );
}
return TRUE;
}
-char is_valid_namespace(char *namespace)
-{
- if (namespace == NULL || *namespace == '\0' || *namespace == '/')
- return 0; // Invalid: Length = 0 or starting with a slash
- while (*namespace)
- {
- if (*namespace != '/' && *namespace != '-' && (*namespace < 'a' || *namespace > 'z')
- && (*namespace < 'A' || *namespace > 'Z')
- && (*namespace < '0' || *namespace > '9'))
- return 0;
- ++namespace;
- }
- if (strstr(namespace, "//") != NULL)
- return 0; // Invalid: Double slash
- if (*(namespace - 1) == '/')
- return 0; // Invalid: Ends in a slash
- return 1;
-}
-
-char is_valid_imagename(char *namespace)
-{
- if (*namespace == '\0' || *namespace == ' ')
- return 0; // Invalid: Length = 0 or starting with a space
- while (*namespace)
- {
- // Check for invalid chars
- if (*namespace != '.' && *namespace != '-' && *namespace != ' '
- && *namespace != '(' && *namespace != ')'
- && (*namespace < 'a' || *namespace > 'z') && (*namespace < 'A' || *namespace > 'Z')
- && (*namespace < '0' || *namespace > '9'))
- return 0;
- ++namespace;
- }
- if (*(namespace - 1) == ' ')
- return 0; // Invalid: Ends in a space
- return 1;
-}
-
void strtolower(char *string)
{
- while (*string)
- {
- if (*string >= 'A' && *string <= 'Z')
- *string += 32;
+ while ( *string ) {
+ if ( *string >= 'A' && *string <= 'Z' ) *string += 32;
++string;
}
}
void remove_trailing_slash(char *string)
{
- char *ptr = string + strlen(string) - 1;
- while (ptr >= string && *ptr == '/')
+ char *ptr = string + strlen( string ) - 1;
+ while ( ptr >= string && *ptr == '/' )
*ptr-- = '\0';
}
+void trim_right(char * const string)
+{
+ char *end = string + strlen( string ) - 1;
+ while ( end >= string && (*end == '\r' || *end == '\n' || *end == ' ' || *end == '\t') )
+ *end-- = '\0';
+}
+
int file_exists(char *file)
{
- int fd = open(file, O_RDONLY);
- if (fd < 0)
- return FALSE;
- close(fd);
+ int fd = open( file, O_RDONLY );
+ if ( fd < 0 ) return FALSE;
+ close( fd );
return TRUE;
}
int file_writable(char *file)
{
- int fd = open(file, O_WRONLY);
- if (fd >= 0)
- {
- close(fd);
+ int fd = open( file, O_WRONLY );
+ if ( fd >= 0 ) {
+ close( fd );
return TRUE;
}
- fd = open(file, O_WRONLY | O_CREAT, 0600);
- if (fd < 0)
- return FALSE;
- close(fd);
- unlink(file);
+ fd = open( file, O_WRONLY | O_CREAT, 0600 );
+ if ( fd < 0 ) return FALSE;
+ close( fd );
+ unlink( file );
+ return TRUE;
+}
+
+int mkdir_p(const char* path)
+{
+ assert( path != NULL );
+ if ( *path == '\0' ) return TRUE;
+ char buffer[strlen( path ) + 1];
+ strcpy( buffer, path );
+ char *current = buffer;
+ char *slash;
+ while ( (slash = strchr( current, '/' )) != NULL ) {
+ *slash = '\0';
+ if ( *buffer != '\0' && mkdir( buffer, 0750 ) != 0 && errno != EEXIST ) return FALSE;
+ *slash = '/';
+ current = slash + 1;
+ }
+ if ( mkdir( buffer, 0750 ) != 0 && errno != EEXIST ) return FALSE;
return TRUE;
}
diff --git a/src/server/helper.h b/src/server/helper.h
index e068abd..c212720 100644
--- a/src/server/helper.h
+++ b/src/server/helper.h
@@ -13,12 +13,12 @@
char parse_address(char *string, dnbd3_host_t *host);
char host_to_string(const dnbd3_host_t *host, char *target, size_t targetlen);
-char is_valid_namespace(char *namespace);
-char is_valid_imagename(char *namespace);
void strtolower(char *string);
void remove_trailing_slash(char *string);
+void trim_right(char * const string);
int file_exists(char *file);
int file_writable(char *file);
+int mkdir_p(const char* path);
static inline int is_same_server(const dnbd3_host_t * const a, const dnbd3_host_t * const b)
{
diff --git a/src/server/image.c b/src/server/image.c
index 2a24092..556e83b 100644
--- a/src/server/image.c
+++ b/src/server/image.c
@@ -13,6 +13,8 @@
#include <sys/types.h>
#include <dirent.h>
#include <zlib.h>
+#include <inttypes.h>
+#include <fcntl.h>
// ##########################################
@@ -25,6 +27,7 @@ pthread_spinlock_t _images_lock;
static int image_load_all_internal(char *base, char *path);
static int image_try_load(char *base, char *path);
static int image_check_blocks_crc32(int fd, uint32_t *crc32list, int *blocks);
+static int64_t image_pad(const char *path, const int64_t currentSize);
// ##########################################
@@ -388,27 +391,7 @@ static int image_try_load(char *base, char *path)
}
if ( fileSize % DNBD3_BLOCK_SIZE != 0 ) {
memlogf( "[INFO] Image size of '%s' is not a multiple of %d, fixing...", path, (int)DNBD3_BLOCK_SIZE );
- const int missing = DNBD3_BLOCK_SIZE - (fileSize % DNBD3_BLOCK_SIZE);
- char buffer[missing];
- memset( buffer, 0, missing );
- int tmpFd = open( path, O_WRONLY | O_APPEND );
- int success = FALSE;
- if ( tmpFd < 0 ) {
- memlogf( "[WARNING] Can't open image for writing, can't fix." );
- } else if ( lseek( tmpFd, fileSize, SEEK_SET ) != fileSize ) {
- memlogf( "[WARNING] lseek failed, can't fix." );
- } else if ( write( tmpFd, buffer, missing ) != missing ) {
- memlogf( "[WARNING] write failed, can't fix." );
- } else {
- success = TRUE;
- }
- if ( tmpFd >= 0 ) close( tmpFd );
- if ( success ) {
- fileSize += missing;
- } else {
- fileSize -= (DNBD3_BLOCK_SIZE - missing);
- }
-
+ fileSize = image_pad( path, fileSize );
}
// 1. Allocate memory for the cache map if the image is incomplete
sprintf( mapFile, "%s.map", path );
@@ -564,6 +547,73 @@ static int image_try_load(char *base, char *path)
}
/**
+ * Create a new image with the given image name and revision id in _basePath
+ * Returns TRUE on success, FALSE otherwise
+ */
+int image_create(char *image, int revision, uint64_t size)
+{
+ assert( image != NULL );
+ assert( size >= DNBD3_BLOCK_SIZE );
+ if ( revision <= 0 ) {
+ printf( "[ERROR] revision id invalid: %d\n", revision );
+ return FALSE;
+ }
+ const int PATHLEN = 2000;
+ char path[PATHLEN], cache[PATHLEN];
+ char *lastSlash = strrchr( image, '/' );
+ if ( lastSlash == NULL ) {
+ snprintf( path, PATHLEN, "%s/%s.r%d", _basePath, image, revision );
+ } else {
+ *lastSlash = '\0';
+ snprintf( path, PATHLEN, "%s/%s", _basePath, image );
+ mkdir_p( path );
+ *lastSlash = '/';
+ snprintf( path, PATHLEN, "%s/%s.r%d", _basePath, image, revision );
+ }
+ if ( file_exists( path ) ) {
+ printf( "[ERROR] Image %s with rid %d already exists!\n", image, revision );
+ return FALSE;
+ }
+ snprintf( cache, PATHLEN, "%s.map", path );
+ size = (size + DNBD3_BLOCK_SIZE - 1) & ~(uint64_t)(DNBD3_BLOCK_SIZE - 1);
+ const int mapsize = IMGSIZE_TO_MAPBYTES(size);
+ // Write files
+ int fdImage = -1, fdCache = -1;
+ fdImage = open( path, O_WRONLY | O_TRUNC, 0640 );
+ fdCache = open( cache, O_WRONLY | O_TRUNC, 0640 );
+ if ( fdImage < 0 ) {
+ printf( "[ERROR] Could not open %s for writing.\n", path );
+ goto failure_cleanup;
+ }
+ if ( fdCache < 0 ) {
+ printf( "[ERROR] Could not open %s for writing.\n", cache );
+ goto failure_cleanup;
+ }
+ // Try cache map first
+ if ( fallocate( fdCache, 0, 0, mapsize ) != 0 ) {
+ const int err = errno;
+ printf( "[ERROR] Could not allocate %d bytes for %s (errno=%d)", mapsize, cache, err );
+ goto failure_cleanup;
+ }
+ // Now write image
+ if ( fallocate( fdImage, 0, 0, size ) != 0 ) {
+ const int err = errno;
+ printf( "[ERROR] Could not allocate %" PRIu64 " bytes for %s (errno=%d)", size, path, err );
+ goto failure_cleanup;
+ }
+ close( fdImage );
+ close( fdCache );
+ return TRUE;
+ //
+ failure_cleanup: ;
+ if ( fdImage >= 0 ) close( fdImage );
+ if ( fdCache >= 0 ) close( fdCache );
+ remove( path );
+ remove( cache );
+ return FALSE;
+}
+
+/**
* Generate the crc32 block list file for the given file.
* This function wants a plain file name instead of a dnbd3_image_t,
* as it can be used directly from the command line.
@@ -575,11 +625,35 @@ int image_generate_crc_file(char *image)
printf( "Could not open %s.\n", image );
return FALSE;
}
+ // force size to be multiple of DNBD3_BLOCK_SIZE
+ int64_t fileLen = lseek( fdImage, 0, SEEK_END );
+ if ( fileLen <= 0 ) {
+ printf( "Error seeking to end, or file is empty.\n" );
+ close( fdImage );
+ return FALSE;
+ }
+ if ( fileLen % DNBD3_BLOCK_SIZE != 0 ) {
+ printf( "File length is not a multiple of DNBD3_BLOCK_SIZE\n" );
+ const int64_t ret = image_pad( image, fileLen );
+ if ( ret < fileLen ) {
+ printf( "Error appending to file in order to make it block aligned.\n" );
+ close( fdImage );
+ return FALSE;
+ }
+ printf( "...fixed!\n" );
+ fileLen = ret;
+ }
+ if ( lseek( fdImage, 0, SEEK_SET ) != 0 ) {
+ printf( "Seeking back to start failed.\n" );
+ close( fdImage );
+ return FALSE;
+ }
char crcFile[strlen( image ) + 4 + 1];
sprintf( crcFile, "%s.crc", image );
struct stat sst;
if ( stat( crcFile, &sst ) == 0 ) {
printf( "CRC File for %s already exists! Delete it first if you want to regen.\n", image );
+ close( fdImage );
return FALSE;
}
int fdCrc = open( crcFile, O_RDWR | O_CREAT, 0640 );
@@ -704,6 +778,33 @@ static int image_check_blocks_crc32(int fd, uint32_t *crc32list, int *blocks)
return TRUE;
}
+static int64_t image_pad(const char *path, const int64_t currentSize)
+{
+ const int missing = DNBD3_BLOCK_SIZE - (currentSize % DNBD3_BLOCK_SIZE );
+ char buffer[missing];
+ memset( buffer, 0, missing );
+ int tmpFd = open( path, O_WRONLY | O_APPEND );
+ int success = FALSE;
+ if ( tmpFd < 0 ) {
+ memlogf( "[WARNING] Can't open image for writing, can't fix %s", path );
+ } else if ( lseek( tmpFd, 0, SEEK_CUR ) != currentSize ) {
+ const int64_t cur = lseek( tmpFd, 0, SEEK_CUR );
+ memlogf( "[WARNING] File size of %s changed when told to extend. (is: %" PRIi64 ", should: %" PRIi64 ")", path, cur, currentSize );
+ } else if ( lseek( tmpFd, currentSize, SEEK_SET ) != currentSize ) {
+ memlogf( "[WARNING] lseek() failed, can't fix %s", path );
+ } else if ( write( tmpFd, buffer, missing ) != missing ) {
+ memlogf( "[WARNING] write() failed, can't fix %s", path );
+ } else {
+ success = TRUE;
+ }
+ if ( tmpFd >= 0 ) close( tmpFd );
+ if ( success ) {
+ return currentSize + missing;
+ } else {
+ return currentSize - (DNBD3_BLOCK_SIZE - missing);
+ }
+}
+
/*
void image_find_latest()
{
diff --git a/src/server/image.h b/src/server/image.h
index 6910395..9e70e6f 100644
--- a/src/server/image.h
+++ b/src/server/image.h
@@ -10,7 +10,7 @@ extern pthread_spinlock_t _images_lock;
int image_is_complete(dnbd3_image_t *image);
-void image_update_cachemap( dnbd3_image_t *image, uint64_t start, uint64_t end, const int set );
+void image_update_cachemap(dnbd3_image_t *image, uint64_t start, uint64_t end, const int set);
int image_save_cache_map(dnbd3_image_t *image);
@@ -22,6 +22,7 @@ dnbd3_image_t* image_free(dnbd3_image_t *image);
int image_load_all(char *path);
+int image_create(char *image, int revision, uint64_t size);
int image_generate_crc_file(char *image);
diff --git a/src/server/memlog.c b/src/server/memlog.c
index f159d96..447d232 100644
--- a/src/server/memlog.c
+++ b/src/server/memlog.c
@@ -48,72 +48,75 @@ static volatile int bufferPos = 0;
void initmemlog()
{
// Use main spinlock to make sure we really init only once
- if (logBuffer) return;
- spin_init(&logLock, PTHREAD_PROCESS_PRIVATE);
- logBuffer = (LogLine *)calloc(LINE_COUNT, sizeof(LogLine));
+ if ( logBuffer ) return;
+ spin_init( &logLock, PTHREAD_PROCESS_PRIVATE );
+ logBuffer = (LogLine *)calloc( LINE_COUNT, sizeof(LogLine) );
}
void memlogf(const char *fmt, ...)
{
- if (!logBuffer) return; // Not initialized yet
+ if ( logBuffer == NULL ) {
+ va_list ap;
+ va_start( ap, fmt );
+ vprintf( fmt, ap );
+ va_end( ap );
+ return; // Not initialized yet
+ }
va_list ap;
int ret;
time_t rawtime;
struct tm *timeinfo;
- time(&rawtime);
- timeinfo = localtime(&rawtime);
- spin_lock(&logLock);
- LogLine *const line = (LogLine *)&(logBuffer[bufferPos % LINE_COUNT]);
- const size_t offset = strftime(line->text, LINE_LEN, "[%d.%m. %H:%M:%S] ", timeinfo);
- if (offset == 0) *line->text = '\0';
- va_start(ap, fmt);
- ret = vsnprintf(line->text + offset, LINE_LEN - offset, fmt, ap);
- va_end(ap);
- char *end = line->text + strlen(line->text);
- while (end > line->text && *--end == '\n') *end = '\0'; // remove trailing \n
+ time( &rawtime );
+ timeinfo = localtime( &rawtime );
+ spin_lock( &logLock );
+ LogLine * const line = (LogLine *)&(logBuffer[bufferPos % LINE_COUNT]);
+ const size_t offset = strftime( line->text, LINE_LEN, "[%d.%m. %H:%M:%S] ", timeinfo );
+ if ( offset == 0 ) *line->text = '\0';
+ va_start( ap, fmt );
+ ret = vsnprintf( line->text + offset, LINE_LEN - offset, fmt, ap );
+ va_end( ap );
+ char *end = line->text + strlen( line->text );
+ while ( end > line->text && *--end == '\n' )
+ *end = '\0'; // remove trailing \n
// glibc 2.0 would return -1 if the buffer was too small
// glibc 2.1 would return the number of bytes required if the buffer was too small
// so to be safe either way, let strlen do the job
- line->len = strlen(line->text);
- if (ret > 0 || line->len > 0) ++bufferPos;
- spin_unlock(&logLock);
- puts(line->text);
+ line->len = strlen( line->text );
+ if ( ret > 0 || line->len > 0 ) ++bufferPos;
+ spin_unlock( &logLock );
+ puts( line->text );
}
char *fetchlog(int maxlines)
{
- if (!logBuffer) return NULL;
- if (maxlines <= 0 || maxlines > LINE_COUNT) maxlines = LINE_COUNT;
+ if ( !logBuffer ) return NULL ;
+ if ( maxlines <= 0 || maxlines > LINE_COUNT ) maxlines = LINE_COUNT;
const int start = MAX(0, bufferPos - maxlines);
int len = 1, i;
//printf("Outputting log from %d to %d\n", start, bufferPos);
- spin_lock(&logLock);
+ spin_lock( &logLock );
// Determine required buffer space for all log lines
- for (i = start; i < bufferPos; ++i)
- {
- if (logBuffer[i % LINE_COUNT].len > 0)
- {
+ for (i = start; i < bufferPos; ++i) {
+ if ( logBuffer[i % LINE_COUNT].len > 0 ) {
len += logBuffer[i % LINE_COUNT].len + 1;
}
}
//printf("Have to allocate %d bytes\n", len);
// Allocate buffer. If this is a bottleneck because of malloc, consider passing a buffer to the function that the caller allocates on the stack
- char *retval = (char *)calloc(len, sizeof(char));
- if (retval == NULL) goto endFunction;
+ char *retval = (char *)calloc( len, sizeof(char) );
+ if ( retval == NULL ) goto endFunction;
// Concatenate all log lines, delimit using '\n'
char *pos = retval;
- for (i = start; i < bufferPos; ++i)
- {
- LogLine *const line = (LogLine *)&(logBuffer[i % LINE_COUNT]);
- if (line->len > 0)
- {
- memcpy(pos, (char *)line->text, line->len);
+ for (i = start; i < bufferPos; ++i) {
+ LogLine * const line = (LogLine *)&(logBuffer[i % LINE_COUNT]);
+ if ( line->len > 0 ) {
+ memcpy( pos, (char *)line->text, line->len );
pos += line->len;
*pos++ = '\n';
}
}
*pos = '\0';
-endFunction:
- spin_unlock(&logLock);
+ endFunction:
+ spin_unlock( &logLock );
return retval;
}
diff --git a/src/server/server.c b/src/server/server.c
index dc374a0..9b6ff30 100644
--- a/src/server/server.c
+++ b/src/server/server.c
@@ -41,6 +41,7 @@
#include "net.h"
#include "altservers.h"
#include "memlog.h"
+#include "globals.h"
#define MAX_SERVER_SOCKETS 50 // Assume there will be no more than 50 sockets the server will listen on
static int sockets[MAX_SERVER_SOCKETS], socket_count = 0;
@@ -68,18 +69,20 @@ void dnbd3_print_help(char *argv_0)
{
printf( "Usage: %s [OPTIONS]...\n", argv_0 );
printf( "Start the DNBD3 server\n" );
- //printf( "-f or --file Configuration file (default /etc/dnbd3-server.conf)\n" );
+ printf( "-c or --config Configuration file (default /etc/dnbd3-server.conf)\n" );
#ifdef _DEBUG
printf( "-d or --delay Add a fake network delay of X µs\n" );
#endif
printf( "-n or --nodaemon Start server in foreground\n" );
- printf( "-r or --reload Reload configuration file\n" );
- printf( "-s or --stop Stop running dnbd3-server\n" );
- printf( "-i or --info Print connected clients and used images\n" );
- printf( "-H or --help Show this help text and quit\n" );
+ //printf( "-r or --reload Reload configuration file\n" );
+ //printf( "-s or --stop Stop running dnbd3-server\n" );
+ //printf( "-i or --info Print connected clients and used images\n" );
+ printf( "-h or --help Show this help text and quit\n" );
printf( "-v or --version Show version and quit\n" );
printf( "Management functions:\n" );
- printf( "--crc [image] Generate crc block list for given image\n" );
+ printf( "--crc [image-file] Generate crc block list for given image\n" );
+ printf( "--create [image-name] --revision [rid] --size [filesize]\n"
+ "\tCreate a local empty image file with a zeroed cache-map for the specified image" );
exit( 0 );
}
@@ -145,17 +148,22 @@ int main(int argc, char *argv[])
int demonize = 1;
int opt = 0;
int longIndex = 0;
- static const char *optString = "f:d:nrsiHV?";
- static const struct option longOpts[] = { { "file", required_argument, NULL, 'f' }, { "delay", required_argument, NULL, 'd' }, {
+ char *paramCreate = NULL;
+ int64_t paramSize = -1;
+ int paramRevision = -1;
+ static const char *optString = "c:d:nrsihv?";
+ static const struct option longOpts[] = { { "config", required_argument, NULL, 'c' }, { "delay", required_argument, NULL, 'd' }, {
"nodaemon", no_argument, NULL, 'n' }, { "reload", no_argument, NULL, 'r' }, { "stop", no_argument, NULL, 's' }, { "info",
- no_argument, NULL, 'i' }, { "help", no_argument, NULL, 'H' }, { "version", no_argument, NULL, 'v' }, { "crc", required_argument,
- NULL, 'crc4' }, { "assert", no_argument, NULL, 'asrt' }, { 0, 0, 0, 0 } };
+ no_argument, NULL, 'i' }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { "crc", required_argument,
+ NULL, 'crc4' }, { "assert", no_argument, NULL, 'asrt' }, { "create", required_argument, NULL, 'crat' }, { "revision",
+ required_argument, NULL, 'rvid' }, { "size", required_argument, NULL, 'size' }, { 0, 0, 0, 0 } };
opt = getopt_long( argc, argv, optString, longOpts, &longIndex );
while ( opt != -1 ) {
switch ( opt ) {
- case 'f':
+ case 'c':
+ _configDir = strdup( optarg );
break;
case 'd':
#ifdef _DEBUG
@@ -180,7 +188,7 @@ int main(int argc, char *argv[])
printf( "INFO: Requesting information...\n\n" );
//dnbd3_rpc_send(RPC_IMG_LIST);
return EXIT_SUCCESS;
- case 'H':
+ case 'h':
case '?':
dnbd3_print_help( argv[0] );
break;
@@ -194,26 +202,49 @@ int main(int argc, char *argv[])
assert( 4 == 5 );
printf( "Assertion 4 == 5 seems to hold. ;-)\n" );
return EXIT_SUCCESS;
+ case 'crat':
+ paramCreate = strdup( optarg );
+ break;
+ case 'rvid':
+ paramRevision = atoi( optarg );
+ break;
+ case 'size':
+ paramSize = strtoll( optarg, NULL, 10 );
+ break;
}
opt = getopt_long( argc, argv, optString, longOpts, &longIndex );
}
- if ( demonize ) daemon( 1, 0 );
+ // One-shots first:
- _basePath = strdup( "/home/sr/vmware/" );
- _vmdkLegacyMode = TRUE;
+ if ( paramCreate != NULL ) {
+ return image_create( paramCreate, paramRevision, paramSize ) ? 0 : EXIT_FAILURE;
+ }
+
+ // No one-shot detected, normal server operation
+
+ if ( _configDir == NULL ) _configDir = strdup( "/etc/dnbd3-server" );
+ globals_loadConfig();
+ if ( _basePath == NULL ) {
+ printf( "ERROR: basePath not set in %s/%s\n", _configDir, CONFIG_FILENAME );
+ exit( EXIT_FAILURE );
+ }
+ if ( demonize ) daemon( 1, 0 );
+ initmemlog();
spin_init( &_clients_lock, PTHREAD_PROCESS_PRIVATE );
spin_init( &_images_lock, PTHREAD_PROCESS_PRIVATE );
altserver_init();
+ memlogf( "DNBD3 server starting.... Machine type: " ENDIAN_MODE );
+
+ if ( altservers_load() < 0 ) {
+ memlogf( "[WARNING] Could not load alt-servers. Does the file exist in %s?", _configDir );
+ }
#ifdef _DEBUG
debug_locks_start_watchdog();
#endif
- initmemlog();
- memlogf( "DNBD3 server starting.... Machine type: " ENDIAN_MODE );
-
// load config file
dnbd3_load_config();
@@ -235,8 +266,7 @@ int main(int argc, char *argv[])
if ( sockets[socket_count] != -1 ) ++socket_count;
#ifdef WITH_IPV6
sockets[socket_count] = sock_listen_any(PF_INET6, PORT);
- if (sockets[socket_count] != -1)
- ++socket_count;
+ if (sockets[socket_count] != -1) ++socket_count;
#endif
if ( socket_count == 0 ) exit( EXIT_FAILURE );
struct sockaddr_storage client;