diff options
Diffstat (limited to 'server/config.c')
-rw-r--r-- | server/config.c | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/server/config.c b/server/config.c new file mode 100644 index 0000000..5dec41e --- /dev/null +++ b/server/config.c @@ -0,0 +1,213 @@ +/* + * server/config.c + */ + + +#include <arpa/inet.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <stdio.h> +#include "dnbd2.h" +#include "tree.h" +#include "file.h" +#include "config.h" + + +char *get_line(char *buf, FILE *file); +dataset_t *parse_dataset_file(const char *filename); +int parse_server(dnbd2_server_t *server, const char *str); + + +/* + * The config file looks like this: + * + * 192.168.178.120 + * 5000 + * /etc/dnbd2/datasets/debian-3.1 192.168.178.119:5005 + * /etc/dnbd2/datasets/suse-10.2 192.168.178.119:5005 192.168.178.118:5005 + * ... + * + */ +int parse_config_file(const char *filename, struct sockaddr_in *sockaddr, + void **tree) +{ + char buf[LINE_SIZE_MAX]; + FILE *file; + + bzero(sockaddr, sizeof(sockaddr)); + sockaddr->sin_family = AF_INET; + + /* Open file. */ + file = fopen(filename, "r"); + if (!file) { + syslog(LOG_ERR, "Could not open config file %s", filename); + return -1; + } + syslog(LOG_NOTICE, "Config file: %s", filename); + + /* Read IP from file. */ + if (!get_line(buf, file) || !inet_aton(buf, &(sockaddr->sin_addr))) { + syslog(LOG_ERR, "Could not read IP."); + return -1; + } + + /* Read port number from file. */ + if (!get_line(buf, file) || + sscanf(buf, "%hu", &(sockaddr->sin_port)) != 1) { + syslog(LOG_ERR, "Could not read port number."); + return -1; + } + sockaddr->sin_port = htons(sockaddr->sin_port); + + syslog(LOG_NOTICE, "IP = %s, Port = %hu", + inet_ntoa(sockaddr->sin_addr), ntohs(sockaddr->sin_port)); + + int datasets = 0; + char server[ALT_SERVERS_MAX][LINE_SIZE_MAX]; + char dsfile[LINE_SIZE_MAX]; + while (get_line(buf, file)) { + + int ret = sscanf(buf, "%s %s %s %s %s", + dsfile, + server[0], + server[1], + server[2], + server[3]) - 1; + + /* Parse a dataset file and put it into a tree-node. */ + dataset_t *dataset = parse_dataset_file(dsfile); + if (!dataset) + goto out_nodsfile; + node_t *data = (node_t *)malloc(sizeof(node_t)); + if (!data) { + syslog(LOG_ERR, + "Could not allocate memory for new Dataset."); + goto out_nodataset; + } + int fd = file_open(dataset->path); + if (fd == -1) { + syslog(LOG_ERR, + "Could not open file or block device %s", + dataset->path); + goto out_nodata; + } + strncpy(data->path, dsfile, FILE_NAME_MAX); + data->ds = dataset; + data->fd = fd; + + /* Parse the list of alterntive servers. */ + int i; + int cnt = 0; + for (i=0 ; i<ret ; i++) + cnt += parse_server(&data->server[cnt], server[i]); + data->servers = cnt; + + /* Check if the Volume-ID-Release-ID pair is already in use. */ + node_t *data2 = tree_find(data, tree); + if (data2) { + syslog(LOG_ERR, + "Vol-ID/Rel-ID already used in Dataset file %s", + data2->path); + goto out_nodata; + } + + /* Insert Dataset into tree. */ + if (tree_insert(data, tree) == -1) { + syslog(LOG_ERR, "Could not insert Dataset into tree."); + goto out_nodata; + } + + datasets++; + continue; + + out_nodata: + free(data); + out_nodataset: + free(dataset); + out_nodsfile: + syslog(LOG_ERR, "Problem parsing %s", dsfile); + } + + syslog(LOG_NOTICE, "Loaded %d Dataset(s).", datasets); + + fclose(file); + return datasets; +} + + +/* + * A dataset config file looks like this: + * + * /path/to/file/or/block/device + * Volume-ID + * Release-ID + */ +dataset_t *parse_dataset_file(const char *filename) +{ + char buf[LINE_SIZE_MAX]; + + FILE *file = fopen(filename, "r"); + if (!file) { + syslog(LOG_ERR, "Could not open Dataset file %s", filename); + return NULL; + } + + dataset_t *dataset = (dataset_t *) malloc(sizeof(dataset_t)); + if (!dataset) { + syslog(LOG_ERR, "Could not allocate memory for new Dataset."); + return NULL; + } + + /* Read file- or block device name from file. */ + if (!get_line(dataset->path, file)) { + syslog(LOG_ERR, "Could not read path to file or block device"); + return NULL; + } + + /* Read Volume-ID from file. */ + if (!get_line(buf, file) || sscanf(buf, "%hu", &(dataset->vid)) != 1) { + syslog(LOG_ERR, "Could not read Volume-ID."); + return NULL; + } + + /* Read Release-ID from file. */ + if (!get_line(buf, file) || sscanf(buf, "%hu", &(dataset->rid)) != 1) { + syslog(LOG_ERR, "Could not read Release-ID."); + return NULL; + } + + fclose(file); + return dataset; +} + + +char *get_line(char *buf, FILE *file) +{ + char *ret = fgets(buf, LINE_SIZE_MAX, file); + + /* change \n with \0 */ + if (ret) + buf[strlen(buf)-1] = '\0'; + + return ret; +} + + +int parse_server(dnbd2_server_t *server, const char *str) +{ + char ip[LINE_SIZE_MAX]; + uint16_t port; + struct in_addr tmp; + + if (sscanf(str, "%[^:]:%hu", ip, &port) != 2) + return 0; + + if (!inet_aton(ip, &tmp)) + return 0; + + memcpy(&server->ip, &tmp, sizeof(uint32_t)); + server->port = htons(port); + + return 1; +} |