#!/usr/bin/perl -w

###########################################################################
# log-debug.pl
# Version 1.0
#
# Chris Adams <cmadams@hiwaay.net>
# http://ro.com/~cadams/files
#
###########################################################################
# This program may be distributed under the terms of either the GNU
# General Public License or the Artistic License, as specified in the
# Perl README file.
###########################################################################
#
# Log debugging info from a PortMaster to a file.  Once started, if you
# specify a log file, it forks and goes into the background.  Send a HUP to
# the process for it to turn off debuging, reset the console, and nicely
# exit.
#
# Requires the Net::Telnet module (available at any CPAN site, try
# http://www.perl.com/CPAN/modules/by-module/Net/)
#
# Options:
#  -h: name or IP address to connect to
#  -t: port (if not standard telnet) to connect to
#  -d: debug flag(s) (additional flags seperated with commas)
#  -u: username (if not !root)
#  -p: password (if not specified, it will be prompted)
#  -f: file to log to (if not STDOUT)
#

use Net::Telnet;
use POSIX;
use Getopt::Std;
use strict;

$Getopt::Std::opt_u = "!root";
$Getopt::Std::opt_p = "";
$Getopt::Std::opt_d = "0x51";
$Getopt::Std::opt_f = "-";
$Getopt::Std::opt_h = "";
$Getopt::Std::opt_t = "23";
getopts ('u:p:d:f:h:t:');
my @debug = split (/,/, $Getopt::Std::opt_d);
if (! $Getopt::Std::opt_h || @ARGV) {
	(my $name = $0) =~ s!.*/!!;
	print <<EOF;
Usage: $name -h <host> [-t <port>] [-d <debug[,<debug>]]
       [-u <user>] [-p <pass>] [-f <outfile>]
EOF
	exit (1);
}

if (! $Getopt::Std::opt_p) {
	$| = 1;
	print "Password: ";
	my $t = POSIX::Termios->new;
	$t->getattr (1);
	my $l = $t->getlflag;
	my $le = $l & ~(&POSIX::ECHO | &POSIX::ICANON);
	$t->setlflag ($le);
	$t->setattr (1, &POSIX::TCSANOW);
	$Getopt::Std::opt_p = <>;
	chomp $Getopt::Std::opt_p;
	$t->setlflag ($l);
	$t->setattr (1, &POSIX::TCSANOW);
	print "\n";
}

$main::quit = 0;
$SIG{HUP} = sub { $main::quit = 1; };
$SIG{INT} = sub { $main::quit = 1; };

my $pm = new Net::Telnet (Timeout => -1);
$pm->open (Host => $Getopt::Std::opt_h, Port => $Getopt::Std::opt_t)
    or die "telnet open: $!";
$pm->waitfor ('/login: /');
$pm->print ($Getopt::Std::opt_u);
$pm->waitfor ('/Password: /');
$pm->print ($Getopt::Std::opt_p);
my ($s) = ($pm->waitfor (String => "Command>", String => "login:"))[1];
die "Invalid password\n" if ($s eq "login:");
$pm->print ("set console");
$pm->waitfor ('/Command> /');
while (defined (my $d = shift @debug)) {
	$pm->print ("set debug $d");
}
$pm->waitfor ('/Command> /');

open (OUTPUT, ">$Getopt::Std::opt_f") or die "can't open output file: $!";
select (OUTPUT); $| = 1;

my $close = sub {
	$pm->print ("set debug off");
	$pm->waitfor ('/Command> /');
	$pm->print ("reset console");
	$pm->waitfor ('/Command> /');
	$pm->print ("logout");
	$pm->close;
	close (OUTPUT);
	exit (0);
};
$SIG{HUP} = $SIG{INT} = $SIG{TERM} = $close;

if ($Getopt::Std::opt_f ne "-") {
	if (! defined (my $pid = fork ())) {
		die "can't fork: $!";
	} elsif ($pid) {
		print STDERR "monitoring process is $pid\n";
		exit (0);
	}
}

while (! $main::quit && defined (my $line = $pm->getline)) {
	my $now = strftime ("%Y-%m-%d %X", localtime (time));
	print OUTPUT "[", $now, "] ", $line;
}
