--- /dev/null
+package Guardian::Config;
+use strict;
+use warnings;
+
+use Exporter qw(import);
+
+our @EXPORT_OK = qw(CheckConfig UseConfig);
+
+# The default config file which is used, if no one has been specified.
+my $configfile = "/etc/guardian/guardian.conf";
+
+# The maximum amount of chars, which a line in the configfile is allowed to contain.
+my $maxlength = "64";
+
+# Hash with default settings. They may be overwritten by settings of the config file.
+my %defaults = (
+ "LogLevel" => "info",
+ "LogFacility" => "syslog",
+ "BlockCount" => "3",
+ "BlockTime" => "86400",
+);
+
+#
+## UseConfig configuration function.
+#
+## This function does the main work. It is responsible for calling the subfunction
+## to read the given config file (or use the default one if none has been specified),
+## and push the returned object to the validate subfunction. Finally the validated
+## settings will be merged with the default ones (existing defaults will be overwritten).
+#
+sub UseConfig ($) {
+ my $file = $_[0];
+
+ # If not file has been specified, use the default one.
+ unless ($file) {
+ $file = $configfile;
+ }
+
+ # Call subfunction to get the settings from config file.
+ # Store the options and values in a temporary hash.
+ my %temp = &ReadConfig($file);
+
+ # Validate config settings.
+ my $error = &CheckConfig(\%temp);
+
+ # As long, as no error message is returned, the config is valid.
+ unless ($error) {
+ # Merge hash with contains the default
+ # and temporary config hash. If both hashes contains
+ # the same keys, the keys+values of the first one (%defaults)
+ # will be overwritten.
+ my %config = (%defaults, %temp);
+
+ # Return the final configuration hash.
+ return %config;
+
+ # If an error message is returned, exit and print the error message.
+ } else {
+ die "Invalid configuration: $error\n";
+ }
+}
+
+#
+## ReadConfig (configfile) function.
+#
+## This function is used to read a given configuration file and store the
+## values into a hash which will be returned.
+#
+sub ReadConfig ($) {
+ my $file = $_[0];
+
+ # Hash to store the read-in configuration options and values.
+ my %config = ();
+
+ # Check if the configfile exists and is read-able.
+ unless (-r "$file") {
+ die "The given configfile ($file) does not exist, or is not read-able: $!\n";
+ }
+
+ # Open the config file and read-in all configuration options and values.
+ open(CONF, "$file") or die "Could not open $file: $!\n";
+
+ # Process line by line.
+ while (my $line = <CONF>) {
+ # Skip comments.
+ next if ($line =~ /\#/);
+
+ # Skip blank lines.
+ next if ($line =~ /^\s*$/);
+
+ # Remove any newlines.
+ chomp($line);
+
+ # Remove any spaces at the start and end of the line.
+ $line =~ s/^\s*//;
+ $line =~ s/\s*$//;
+
+ # Check line lenght, skip it, if it is longer than, the
+ # allowed maximum.
+ my $length = length("$line");
+ next if ($length gt $maxlength);
+
+ # Splitt line into two parts.
+ my ($option, $value) = split (/=/, $line);
+
+ # Add config option and value to the config hash.
+ $config{$option} = $value;
+ }
+
+ # Close the config file.
+ close(CONF);
+
+ # Return the configuration hash.
+ return %config;
+}
+
+#
+## The CheckConfig function.
+#
+## This function is responsible to validate configure options which has
+## to be passed as a hash. It will return an error message which provides some
+## deeper details, if any problems have been detected.
+#
+sub CheckConfig (\%) {
+ # Dereference the given hash-ref and store
+ # them into a new temporary hash.
+ my %config = %{ $_[0] };
+
+ # If a BlockTime has been configured, check if the value is a natural number.
+ if (exists($config{BlockTime})) {
+ # Get the configured value for "BlockTime".
+ my $value = $config{BlockTime};
+
+ # Call subroutine for validation.
+ my $error = &check_number("$value");
+
+ # If the check fails, immediately return an error message.
+ if ($error) {
+ return "Invalid BlockTime: $error";
+ }
+ }
+
+ # If a BlockCount has been configured, check if the value is a natural number.
+ if (exists($config{BlockCount})) {
+ # Get the configured value for "BlockCount".
+ my $value = $config{BlockCount};
+
+ # Call subroutine for validation.
+ my $error = &check_number("$value");
+
+ # If the check fails, immediately return an error message.
+ if ($error) {
+ return "Invalid BlockCount: $error";
+ }
+ }
+
+ # XXX - add check for validating the configured loglevel.
+
+ # The config looks good, so return nothing (no error message).
+ return undef
+}
+
+#
+## The check_number subroutine.
+#
+## This simple subroutine is used to check if a given string is numeric
+## and contains a natural number which has to be greater than zero.
+#
+sub check_number ($) {
+ my $input = $_[0];
+
+ # Check if the input is a natural number.
+ unless ($input =~ /^\d+$/) {
+ return "$input is not a natural number";
+ }
+
+ # Check if the number is greater than zero.
+ unless ($input gt "0") {
+ return "$input has to be greater than zero";
+ }
+
+ # Input is okay, return no error message (nothing).
+ return undef;
+}
+
+1;