#!/usr/bin/perl

# This program reads Captrap's configuration and generates suitable MySQL
# commands for creating a pmacct database that Captrap can use.

# Copyright 2009 Corey Hickey


# This file is part of Captrap.
#
# Captrap 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 3 of the License, or
# (at your option) any later version.
#
# Captrap 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.
#
# You should have received a copy of the GNU General Public License
# along with Captrap.  If not, see <http://www.gnu.org/licenses/>.


use strict;
use warnings FATAL => 'all';

use DBI;

# for development using a different Captrap module
use lib "lib";
use Captrap qw(:misc :actions :config :db);


# -----------------------------------------------------------------------------
# printing
# -----------------------------------------------------------------------------

# print main help info
sub usage {
  my $common = shift; # unused
  my $actions = mk_actions();
  my $actions_text = describe_actions($actions);
  print "
This is a script for printing MySQL statements that create a pmacct database
and tables suitable for Captrap. Specifically, the statements printed: 
1. Create the database (unless it already exists).
2. Create \"acct\" and \"macs\" tables.
3. Grant the pmacctd user necessary mysql privileges.
4. Grant the captrap user necessary mysql privileges.

The database name, table names, and user/password information are read from
Captrap's configuration files, which should be set up prior to running this
script.


captrap_mkdb [ACTION] [[ACTION-PARAMETERS]] ...

ACTIONS

$actions_text

EXIT STATUS

0              Everything is ok.

1              No arguments given; usage information was shown.

2              Invalid argument.

3              There was a problem executing an action.


EXAMPLES

Print out statements:
captrap_mkdb -print

Execute the statements:
captrap_mkdb -print | mysql

Use this if you need to enter your MySQL password manually:
captrap_mkdb -print | mysql -u root -p
"
}


# make a list of statements to execute
sub mk_statements {
  my $common = shift;
  my $dbh = $common->{dbh};
  my $config = $common->{config};
  my $config_priv = parse_config_priv($config, 1);
  my ($priv_user, $priv_pass) =
      @{$config_priv}{'db_user_priv', 'db_password_priv'};
  my $states = $config->{states};
  $states = [ map { quote_sql($dbh, $_) } @$states ]; # quote them
  $states = join(", ", @$states); # collapse to scalar, joined with commas
  # some things should not be quoted, so they just get string-interpolated
  return [
    {
      stmt => "CREATE DATABASE IF NOT EXISTS $config->{db_database}",
      args => [],
    },
    {
      stmt => "USE $config->{db_database}",
      args => [ ],
    },
    {
      stmt =>
"# make the main pmacct table
CREATE TABLE IF NOT EXISTS $config->{db_table_acct} (
  mac_dst CHAR(17) NOT NULL,
  packets INT UNSIGNED NOT NULL,
  bytes BIGINT UNSIGNED NOT NULL,
  stamp_inserted DATETIME NOT NULL,
  stamp_updated DATETIME,
  PRIMARY KEY (mac_dst, stamp_inserted)
)",
      args => [ ],
    },
    {
      stmt =>
"# make the MAC address table
CREATE TABLE IF NOT EXISTS $config->{db_table_macs} (
  mac CHAR(17) UNIQUE KEY NOT NULL,
  state ENUM($states) NOT NULL,
  comment TEXT(40)
)",
      args => [],
    },
    {
      stmt =>
"# create a read-only Captrap user
GRANT
  SELECT
  ON $config->{db_database}.*
  TO ?@?
  IDENTIFIED BY ?",
      args => [
        $config->{db_user},
        $config->{captrap_host},
        $config->{db_password},
      ],
    },
    {
      stmt =>
"# create a read/write pmacctd user
GRANT
  SELECT, INSERT, UPDATE, DELETE, LOCK TABLES
  ON $config->{db_database}.*
  TO ?@?
  IDENTIFIED BY ?",
      args => [
        $priv_user,
        $config->{captrap_host},
        $priv_pass
      ],
    },
  ];
}


# print out statements for making a database
sub mkdb {
  my $common = shift;
  my $dbh = $common->{dbh};
  my $config = $common->{config};
  my $states = $config->{states};
  $states = [ map { "'$_'" } @$states ]; # add single-quotes
  $states = join(", ", @$states); # collapse to scalar, joined with commas
  foreach my $stmt (@{mk_statements($common)}) {
    print quote_sql_stmt($dbh, $stmt->{stmt}, $stmt->{args}), ";\n\n";
  }
}

# -----------------------------------------------------------------------------
# actions info
# -----------------------------------------------------------------------------

# return a hash of action info
sub mk_actions {
  my $actions = mk_ixhash();
  %$actions = (
    "-help" => {
      func => \&usage,
      args => [],
      desc => "
          Print this usage information.
      ",
    },
    "-print" => {
      func => \&mkdb,
      args => [],
      desc => "
          Print MySQL statements.
      ",
    },
  );
  return $actions;
}


# -----------------------------------------------------------------------------


# parse the arguments and take actions
if (! @ARGV) {
  usage();
  exit(1);
}
my $actions = mk_actions();
check_args(\@ARGV, $actions);

my $config = parse_config();
my $common = {
  config => $config,
};

do_args($common, \@ARGV, $actions);

exit(0);
