#!/usr/bin/perl
#
# scass2dhcpconf - Perl script to read the DHCP data from the SCASS tables
# and generate dhcp.conf files from it.
#
# usage: scass2dhcpconf [-t|-f] [net_name[,netname]]
#           -t => test mode, return number of nets needing dump, test either
#                 net_names given as commandline argument or all if none
#                 given
#           -f => force dump, dumps either list of nets given on the command
#                 line or all if none given, returns number of nets dumped.
#           Normally, checks the nets listed on the commandline and dumps
#           them if they have the do_commit flag set. Otherwise checks all
#           nets and dumps them if they have the do_commit flag set.
#
#           All dumped nets have their do_commit flag set to fales and their
#           last_dump timestamp set to current_timestamp.
#
#  author: Alexander Schreiber <als@thangorodrim.de>
#
#  version: $Id: scass2dhcpconf,v 1.5 2002/09/15 22:56:55 als Exp $
#
#
# scass.fes - The backendsystem of SCASS (System Configuration and
#             Administration Support System)
#
# Copyright (C) 2002  Alexander Schreiber <als@thangorodrim.de>
#
# This program is free software; you can redistribute it and/or modify 
# it under the terms of the GNU General Public License as published by 
# the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
# 
# This program is distributed in the hope that it will be useful, but 
# WITHOUT ANY WARRANTY; without even the implied warranty of  
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.


require("../common/load_config.pl");
require("../common/load_config_db.pl");
require("../common/db_connect.pl");

use DBI;

use strict;

sub find_nets_for_commit {
# find nets flagged for commit
# parameters: $dbh = database handle
# returns: list of id of nets flagged for commit, may be empty

    my $dbh = shift;

    my $sql;
    my $sth;
    my $data;
    my @net_list;
    my %config;

    $sql = "SELECT id from dhcp_net where do_commit = true";

    $sth = $dbh->prepare($sql);
    $sth->execute;
    while ( $data = $sth->fetchrow_hashref ) {
        unshift(@net_list, $data->{id});
    }

    return @net_list;
}


sub load_modules {
# loads any additionally modules found in $SCASS.BESBase/DHCP/modules
# and $SCASS.BESBase/common (only the *.pm files!)
# parameters: $dbh -> database handle
# returns: 0 on success, -1 on failure

    my $dbh = shift;
 
    my $modules_dir;
    my $module_name;
    my $dir_entry;
    my %config;

    %config = &get_config_from_db($dbh);

    $modules_dir = "$config{'SCASS.BESBase'}/DHCP/modules";
    unless ( -d $modules_dir ) {
        print STDERR "Modules directory $modules_dir does not exist!\n";
        return -1;
    }
    opendir(MOD_DIR, $modules_dir) or die "failed to opendir($modules_dir)";
#    print "loading modules: ";
    while ( $dir_entry = readdir(MOD_DIR) ) {
        $module_name = "$modules_dir/$dir_entry";
        if ( ( -f $module_name ) and $module_name =~ /\.pm$/ ) {
#            print "$dir_entry ";
            require($module_name);
        }
    }
    closedir(MOD_DIR);

    $modules_dir = "$config{'SCASS.BESBase'}/common";
    unless ( -d $modules_dir ) {
#        print STDERR "Modules directory $modules_dir does not exist!\n";
        return -1;
    }
    opendir(MOD_DIR, $modules_dir) or die "failed to opendir($modules_dir)";
    while ( $dir_entry = readdir(MOD_DIR) ) {
        $module_name = "$modules_dir/$dir_entry";
        if ( ( -f $module_name ) and $module_name =~ /\.pm$/ ) {
#            print "$dir_entry ";
            require($module_name);
        }
    }
    closedir(MOD_DIR);

#    print " [done].\n";

    return 0;
}




sub dump_net_file {
# generate net files from database
# parameters: $dbh -> database handle, $net_id -> (database) id of net,
#             $net_type -> type of net
# returns: (0, '') in case of success, (-1, $message) in case of trouble

    my $dbh = shift;
    my $net_id = shift;
    my $net_type = shift;

    my $handler;
    my $handler_module;
    my %config;
    my ($retval, $message);

    my $handled = 0;

    if ( $net_type eq '' ) {
        print STDERR "no net type specified, skipping\n";
        return;
    }

    %config = &get_config_from_db($dbh);

    if ( $net_type eq 'ISC-DHCPd' ) {
        ($retval, $message) = &dump_net_file_isc_dhcp($dbh, $net_id);
        if ( $retval < 0 ) {
            return ($retval, $message);
        }
        $handled++;
    }


    if ( $handled > 1 ) {
        print STDERR "internal fuckup, net handled more than once!\n";
        return (-1, "net handled more than once");
    }

    if ( $handled == 0 ) {
        print STDERR "no valid handler for net_type found!\n";
        return (-1, "no handler found");
    }

    return (0, '');
}




# ##MAIN##

my $dsn;
my $dbh;
my @net_list;
my $net;
my $result;
my $message;
my (%config, %db_access);
my $work;
my $test_only = 0;
my @test_nets;
my $test_net;
my $data;
my $nets_found;
my $sql;
my $sth;
my $force_dump = 0;
my @dump_nets;
my $nets_dumped;
my @dumped_nets;


%db_access = &load_config();

$dsn = "dbi:Pg:dbname=$db_access{DBName} host=$db_access{'DBHost'}";
$dbh = &db_connect($dsn, $db_access{'DBUser'}, $db_access{'DBPassword'});

$dbh->begin_work or die "Failed to setup transaction!\n";

&load_modules($dbh);

%config = &get_config_from_db($dbh);


# option processing
if ( $ARGV[0] eq '-t' ) { # set test mode
    $test_only = 1;
    foreach $work ( @ARGV ) {
        if ( ($work ne '-t') and ( $work ne '-f') ) {
            push(@test_nets, $work);
        }
    }
}

if ( $ARGV[0] eq '-f' ) { # set forced dump mode
    $force_dump = 1;
}

foreach $work ( @ARGV ) {
    if ( ($work ne '-t') and ( $work ne '-f') ) {
        push(@dump_nets, $work);
    }
}

@net_list = &find_nets_for_commit($dbh);


# handle test mode
if ( $test_only ) {
    if ( @test_nets == () ) { # no nets to test explicitly
        $work = scalar(@net_list);
        $dbh->commit or die "Failed to commit transaction!\n";
        $dbh->disconnect;
        exit($work);  # return number of nets found
    } else { # test for explicitly named nets
        $nets_found = 0;
        foreach $test_net ( @test_nets ) {
            $sql = "select id from dhcp_net where do_commit = true ";
            $sql .= "and net_name = '$test_net'";
            $sth = $dbh->prepare($sql);
            $sth->execute;
            $work = 0;
            while ( $data = $sth->fetchrow_hashref ) {
                $work++;
            }
            if ( $work != 0 ) {
                $nets_found++;
            }
        }
        $dbh->commit or die "Failed to commit transaction!\n";
        $dbh->disconnect;
        exit($nets_found);
    }
}


# handle force mode
if ( $force_dump == 1 )  {
    $nets_dumped = 0;
    if ( @dump_nets == () ) { # no nets explicitly listed, dump all
        $sql = "select id from dhcp_net";
        $sth = $dbh->prepare($sql);
        $sth->execute;
        while ( $data = $sth->fetchrow_hashref ) {
            $net = $data->{id};
            ($result, $message) = &dump_net_file($dbh, $net, 
                                                  $config{'DNSType'});
            unshift(@dumped_nets, $net);
            if ( $result == -1 ) {
                print STDERR "dumping net failed: id = |$net|, ";
                print STDERR "message = |$message|\n";
            } else {
                $nets_dumped++;
            }
        }
    } else { # dump only the specified nets
        foreach $work ( @dump_nets ) {
            $sql = "select id from dhcp_net where net_name = '$work'";
            $sth = $dbh->prepare($sql);
            $sth->execute;
            while ( $data = $sth->fetchrow_hashref ) {
                $net = $data->{id};
                ($result, $message) = &dump_net_file($dbh, $net, 
                                                      $config{'DHCPType'});
                unshift(@dumped_nets, $net);
                if ( $result == -1 ) {
                    print STDERR "dumping net failed: id = |$net|, ";
                    print STDERR "message = |$message|\n";
                } else {
                    $nets_dumped++;
                }
            }
        }
    }
    $dbh->commit or die "Failed to commit transaction!\n";
    $dbh->disconnect;
    exit($nets_dumped);
}







# Still here? So we are doing normal operations
#

if ( @dump_nets != () ) { # process explicitly given list
    foreach $work ( @dump_nets ) {
        $sql = "select id from dhcp_net where net_name = '$work'";
        $sql .= " and do_commit = true";
        $sth = $dbh->prepare($sql);
        $sth->execute;
        while ( $data = $sth->fetchrow_hashref ) {
            $net = $data->{id};
            ($result, $message) = &dump_net_file($dbh, $net,
                                                  $config{'DHCPType'});
            unshift(@dumped_nets, $net);
            if ( $result == -1 ) {
                print STDERR "dumping net failed: id = |$net|, ";
                print STDERR "message = |$message|\n";
            } else {
                $nets_dumped++;
            }
        }
    }
} else { # none given, process all
    foreach $net ( @net_list ) {
        ($result, $message) = &dump_net_file($dbh, $net, $config{'DHCPType'});
        unshift(@dumped_nets, $net);
        if ( $result == -1 ) {
            print STDERR "dumping net failed: id = |$net|, ";
            print STDERR "message = |$message|\n";
        } else {
            $nets_dumped++;
        }
    }
}


$dbh->commit or die "Failed to commit transaction!\n";
$dbh->disconnect;

exit($nets_dumped);



