#!/usr/local/bin/perl
#
# dump 3com vlan info
#
# Jim Trocki
#
# $Id: 3cvlan,v 1.2 1999/05/15 17:30:05 trockij Exp $
#
# Copyright (C) 1998 Jim Trocki
#
#    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.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
use A3Com::Sys;
use Getopt::Std;

sub help;
sub write_vlan;
sub write_failure;

getopts ("hdf:p:r:", \%opt);

help() if ($opt{"h"} || (@ARGV == 0 && !$opt{"r"}));

$PATH = $opt{"p"} || ".";
die "$PATH does not exist\n" if (! -d $PATH || ! -w $PATH);

if ($opt{"d"}) {
    my @t = localtime;
    my $DATE = sprintf ("%02d%02d%04d-%02d%02d",
    	$t[4]+1, $t[3], 1900 + $t[5], $t[2], $t[1]);
    $PATH = "$PATH/$DATE-vlanconf";
    if (! -d $PATH) {
	if (!mkdir ($PATH, 0755)) {
	    die "could not mkdir $PATH: $!\n";
	}
    }
}

$PRINT_DATE = localtime;

if ($opt{"f"}) {
    $FAILURES = "$PATH/$opt{f}";
} else {
    $FAILURES = "$PATH/failures";
}


#
# host list
#
if ($opt{"r"}) {
    die "$opt{r} does not exist\n" if (! -f $opt{"r"});
    open (I, $opt{"r"}) || die "could not open $opt{r}: $!\n";
    while (<I>) {
    	next if (/^\s*#/ || /^\s*$/);
	my ($h) = (/^\s*(\S+)/);
	push (@HOSTS, $h);
    }
    close (I);
} else {
    @HOSTS = @ARGV;
}


#
# get login info
#
if (-t STDIN) {
    print STDERR "Login: ";
}
chomp ($LOGIN = <STDIN>);

$COMM  = A3Com::Sys::get_password ("Password: ");

$LOGIN = "read" if ($LOGIN =~ /^\s*$/);


$failures = 0;

foreach my $HOST (@HOSTS) {
    print STDERR sprintf ("%-15s ", $HOST);

    my ($r, $v) = A3Com::Sys::get_vlaninfo (
	host => $HOST,
	login => $LOGIN,
	password => $COMM,
    );

    if (!defined $r) {
	print STDERR "failure: $v\n";
	write_failure ($HOST, $v) ||
	    print STDERR "  could not write failure file: $!\n";
	$failures++;
	next;
    }

    my $err = write_vlan ($HOST, $v);

    if ($err ne "") {
    	write_failure ($HOST, $err) ||
	    print STDERR "  error writing failure: $!\n";
	$failures++;

    } else {
    	print STDERR "OK\n";
    }
}

exit $failures;


#
# help
#
sub help {
    print <<EOF;
usage: 3cvlan [-d] [-f failure-file] [-p path] host [host...]
usage: 3cvlan [-d] [-f failure-file] [-p path] -r file

    -d         create a directory named after the date to store files
    -p path    path where output files will be created
    -f file    file which stores info about failed hosts
    -r file    get list of switches from this file, one per line, ignoring comments

    Login name and password is accepted from an interactive prompt if
    stdin is a tty, otherwise from stdin w/o a prompt.

EOF
    exit;
}


#
# append failure to a file
#
sub write_failure {
    my ($h, $err) = @_;

    open (O, ">>$FAILURES") || return undef;
    print O ("$h $err\n") || return undef;
    close (O) || return undef;
}


#
# write VLAN info to file
#
sub write_vlan {
    my ($HOST, $v) = @_;

    if (!open (O, ">$PATH/$HOST.vlan")) {
    	return "failure: $!";
    }

    print O "$HOST $PRINT_DATE\n";

    foreach my $vlan (sort {$a <=> $b} keys %{$v}) {
    	print O <<EOF;
VLAN: $vlan
	name  : $v->{$vlan}->{name}
	type  : $v->{$vlan}->{type}
	ports : $v->{$vlan}->{ports}
EOF
	if (defined $v->{$vlan}->{"protocol"}) {
	    print O <<EOF;
	prot  : $v->{$vlan}->{"protocol"}
	l3addr: $v->{$vlan}->{"l3addr"}
EOF
	}

	print O <<EOF;
	tags  :
EOF

    	foreach my $port (sort {$a <=> $b} keys %{$v->{$vlan}->{"porttags"}}) {
	    print O sprintf ("\t\t%2d: %s\n",
		    $port, $v->{$vlan}->{"porttags"}->{$port});
	}
    }

    print O "\n";
    close (O);

    return "";
}
