From 96b3a0feb963466447ca8dbc571bc5f670d533cc Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Thu, 1 Aug 2013 18:14:15 +0200 Subject: [SERVER] Add command line options to create empty image of certain size with empty cache map (so it needs an uplink server) --- src/server/altservers.c | 48 ++++++++++++ src/server/altservers.h | 4 + src/server/globals.c | 29 ++++++++ src/server/globals.h | 9 ++- src/server/helper.c | 189 ++++++++++++++++++++---------------------------- src/server/helper.h | 4 +- src/server/image.c | 143 ++++++++++++++++++++++++++++++------ src/server/image.h | 3 +- src/server/memlog.c | 75 ++++++++++--------- src/server/server.c | 70 +++++++++++++----- 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 #include #include @@ -12,6 +13,7 @@ #include #include #include +#include #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 +#include +#include +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 #include #include +#include +#include #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, "", (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, "", (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 #include #include +#include +#include // ########################################## @@ -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 ); @@ -563,6 +546,73 @@ static int image_try_load(char *base, char *path) return function_return; } +/** + * 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, @@ -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; -- cgit v1.2.3-55-g7522