#include <glib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <popt.h>
#include "netconsole.h"
#include "netdumpclient.h"
#include "configuration.h"
#include "server.h"
NetdumpConfiguration config;
char *netdump_dir_prefix = NETDUMP_DIR_PREFIX;
enum ConfigType {
CONFIG_NONE,
CONFIG_BOOLEAN,
CONFIG_INT,
CONFIG_UINT32,
CONFIG_UINT16,
CONFIG_STRING
};
struct ConfigData {
char *name;
enum ConfigType type;
int offset;
void *default_value;
};
/* retrive a structure offset */
#ifdef offsetof
#define CONFIG_OFFSET(field) ((int) offsetof (NetdumpConfiguration, field))
#else /* !offsetof */
#define CONFIG_OFFSET(field) ((int) ((char*) &((NetdumpConfiguration *) 0)->field))
#endif /* !offsetof */
struct ConfigData config_data[] =
{
{ "port", CONFIG_UINT16, CONFIG_OFFSET(port), GINT_TO_POINTER (NETDUMP_PORT) },
{ "max_concurrent_dumps", CONFIG_INT, CONFIG_OFFSET(max_concurrent_dumps), GINT_TO_POINTER (4) },
{ "daemon", CONFIG_BOOLEAN, CONFIG_OFFSET(daemon), GINT_TO_POINTER (0) },
{ "pidfile", CONFIG_STRING, CONFIG_OFFSET(pidfile), NULL },
{ "dumpdirprefix", CONFIG_STRING, CONFIG_OFFSET(dumpdirprefix), NETDUMP_DIR_PREFIX },
{ "secure", CONFIG_INT, CONFIG_OFFSET(secure), GINT_TO_POINTER (1) },
{ "space_check", CONFIG_INT, CONFIG_OFFSET(space_check), GINT_TO_POINTER (1) },
};
#define NUM_CONFIG_DATA (sizeof(config_data)/sizeof(struct ConfigData))
static const GScannerConfig netdump_config_scanner_config =
{
(
" \t\n"
) /* cset_skip_characters */,
(
G_CSET_a_2_z
"_"
G_CSET_A_2_Z
) /* cset_identifier_first */,
(
G_CSET_a_2_z
"_-0123456789"
G_CSET_A_2_Z
) /* cset_identifier_nth */,
( "#\n" ) /* cpair_comment_single */,
TRUE /* case_sensitive */,
FALSE /* skip_comment_multi */,
TRUE /* skip_comment_single */,
FALSE /* scan_comment_multi */,
TRUE /* scan_identifier */,
TRUE /* scan_identifier_1char */,
FALSE /* scan_identifier_NULL */,
TRUE /* scan_symbols */,
FALSE /* scan_binary */,
FALSE /* scan_octal */,
TRUE /* scan_float */,
TRUE /* scan_hex */,
FALSE /* scan_hex_dollar */,
FALSE /* scan_string_sq */,
TRUE /* scan_string_dq */,
TRUE /* numbers_2_int */,
FALSE /* int_2_float */,
FALSE /* identifier_2_string */,
TRUE /* char_2_token */,
FALSE /* symbol_2_token */,
FALSE /* scope_0_fallback */,
};
typedef enum {
CONFIG_TOKEN_BOOLEAN = G_TOKEN_LAST
} PrefsTokenType;
static void
config_set_defaults(void)
{
int i;
char *ptr;
for (i=0;i<NUM_CONFIG_DATA;i++) {
ptr = (char *)&config + config_data[i].offset;
switch (config_data[i].type) {
case CONFIG_BOOLEAN:
case CONFIG_INT:
*(int *)ptr = GPOINTER_TO_INT (config_data[i].default_value);
break;
case CONFIG_UINT32:
*(guint32 *)ptr = GPOINTER_TO_INT (config_data[i].default_value);
break;
case CONFIG_UINT16:
*(guint16 *)ptr = GPOINTER_TO_INT (config_data[i].default_value);
break;
case CONFIG_STRING:
if (config_data[i].default_value != NULL) {
*(char **)ptr = (char *)malloc(strlen(config_data[i].default_value) + 1);
if (*(char **)ptr != NULL) {
strncpy(*(char **)ptr, config_data[i].default_value, strlen(config_data[i].default_value));
(*(char **)ptr)[strlen(config_data[i].default_value)] = '\0';
}
else {
syslog(LOG_ERR, "Cannot malloc\n");
exit(1);
}
}
else
ptr = (char *)NULL;
break;
case CONFIG_NONE:
break;
}
}
}
static guint
config_parse_line(GScanner *scanner)
{
guint token;
int symbol_nr;
char *ptr;
token = g_scanner_get_next_token(scanner);
if (token != G_TOKEN_SYMBOL)
return G_TOKEN_SYMBOL;
symbol_nr = GPOINTER_TO_INT(scanner->value.v_symbol);
token = g_scanner_get_next_token(scanner);
if (token != G_TOKEN_EQUAL_SIGN)
return G_TOKEN_EQUAL_SIGN;
token = g_scanner_get_next_token(scanner);
ptr = (unsigned char *)&config + config_data[symbol_nr].offset;
switch (config_data[symbol_nr].type) {
case CONFIG_BOOLEAN:
if (token != G_TOKEN_IDENTIFIER)
return G_TOKEN_IDENTIFIER;
if (strcasecmp(scanner->value.v_string, "true")==0)
*(int *)ptr = 1;
else
*(int *)ptr = 0;
break;
case CONFIG_INT:
if (token != G_TOKEN_INT)
return G_TOKEN_INT;
*(int *)ptr = scanner->value.v_int;
break;
case CONFIG_UINT32:
if (token != G_TOKEN_INT)
return G_TOKEN_INT;
*(guint32 *)ptr = scanner->value.v_int;
break;
case CONFIG_UINT16:
if (token != G_TOKEN_INT)
return G_TOKEN_INT;
*(guint16 *)ptr = scanner->value.v_int;
break;
case CONFIG_STRING:
if (token != G_TOKEN_STRING)
return G_TOKEN_STRING;
if (*(char **)ptr != NULL)
free(*(char **)ptr);
*(char **)ptr = (char *)malloc(strlen(scanner->value.v_string) + 1);
if (*(char **)ptr != NULL) {
strncpy(*(char **)ptr, scanner->value.v_string, strlen(scanner->value.v_string));
(*(char **)ptr)[strlen(scanner->value.v_string)] = '\0';
}
else {
syslog(LOG_ERR, "Cannot malloc\n");
exit(1);
}
break;
case CONFIG_NONE:
break;
}
return G_TOKEN_NONE;
}
static void
msg_handler (GScanner *scanner,
gchar *message,
gint is_error)
{
char *msg;
g_return_if_fail (scanner != NULL);
msg = g_strdup_printf ("Error parsing %s at line %d: %s", scanner->input_name, scanner->line, message);
if (is_error)
syslog (LOG_ERR, "%s", msg);
else
syslog (LOG_WARNING, "%s", msg);
fprintf (stderr, "%s\n", msg);
g_free (msg);
}
static void
config_load (const char *filename)
{
int i;
int fd;
GScanner *scanner;
guint expected_token;
fd = open(filename, O_RDONLY);
if (fd < 0) {
return;
}
scanner = g_scanner_new ((GScannerConfig *) &netdump_config_scanner_config);
g_scanner_input_file (scanner, fd);
scanner->input_name = filename;
scanner->msg_handler = msg_handler;
g_scanner_freeze_symbol_table(scanner);
for (i = 0; i < NUM_CONFIG_DATA; i++)
if (config_data[i].type != CONFIG_NONE) {
g_scanner_add_symbol(scanner, config_data[i].name,
GINT_TO_POINTER(i));
}
g_scanner_thaw_symbol_table(scanner);
while (1) {
if (g_scanner_peek_next_token(scanner) == G_TOKEN_EOF) {
break;
}
expected_token = config_parse_line(scanner);
if (expected_token != G_TOKEN_NONE) {
gchar *symbol_name;
gchar *msg;
msg = NULL;
symbol_name = NULL;
g_scanner_unexp_token (scanner,
expected_token,
NULL,
"keyword",
symbol_name,
msg,
TRUE);
}
}
g_scanner_destroy (scanner);
close(fd);
}
static int intarg;
static struct poptOption optionsTable[] = {
{ "port", 'p', POPT_ARG_INT, &intarg, 'p',
"ip port to listen on", "6666" },
{ "concurrent", 'c', POPT_ARG_INT, &config.max_concurrent_dumps, 0,
"max number of concurrent dumps", "4" },
{ "daemon", 'd', POPT_ARG_NONE, &config.daemon, 0,
"run in background as a daemon", NULL },
{ "pidfile", 'P', POPT_ARG_STRING, &config.pidfile, 0,
"file in which to store the pid", "path" },
{ "dumpdirprefix", 'D', POPT_ARG_STRING, &config.dumpdirprefix, 0,
"dir in which to store dumps", "/var/spool/netdump" },
{ "secure", 's', POPT_ARG_INT, &config.secure, 0,
"use ssh to send client identification", "1" },
{ "space_check", 'S', POPT_ARG_INT, &config.space_check, 0,
"verify that space is available for the dumpfile", "1" },
POPT_AUTOHELP
{ NULL, 0, 0, NULL, 0 }
};
static void
parse_argument (char c)
{
switch (c)
{
case 'p':
config.port = intarg;
break;
}
}
void
config_init (int argc, char *argv[])
{
signed char c;
poptContext optCon; /* context for parsing command-line options */
/* Set the default values */
config_set_defaults();
config_load ("/usr/local/etc/netdump.conf");
optCon = poptGetContext("netdump-server", argc, (const char **)argv,
optionsTable, 0);
while ((c = poptGetNextOpt(optCon)) >= 0)
parse_argument (c);
}
syntax highlighted by Code2HTML, v. 0.9.1