1#!/usr/local/bin/perl
2##
3## @PACKAGE@ @VERSION@
4@copyright@
5#
6#  RANCID - Really Awesome New Cisco confIg Differ
7#
8#  rancid - generalized rancid module; command schedule is derived from the
9#	    rancid.types.{base,conf} configurations.
10#
11# usage: rancid [-dhltCV] -t device_type [-f filename | hostname]
12#
13use 5.010;
14use strict 'vars';
15use warnings;
16no warnings 'uninitialized';
17use Exporter;
18use Getopt::Std;
19our($opt_d, $opt_f, $opt_h, $opt_l, $opt_t, $opt_C, $opt_V);
20getopts('dfhlt:CV');
21BEGIN {
22    push(@INC, "@pkglibdir@");
23}
24use rancid;
25our @ISA = qw(Exporter rancid);
26
27sub usage()
28{
29    print STDERR "rancid [-dhlCV] -t device_type [-f filename | hostname]\n";
30    exit 64;
31}
32
33if ($opt_h) {
34    usage();
35}
36
37# basic initialization
38rancidinit();
39
40# load device type spec, build @commandtable and load modules
41if (loadtype($devtype)) {
42    die "Couldn't load device type spec for $rancid::devtype\n";
43}
44if (! defined($lscript)) {
45    die "login script not defined for device type $rancid::devtype\n";
46}
47# if the first word of $script is not us (this script), exec the given
48# script.
49my(@script) = split(/\s+/, $script);
50if (which($script[0]) ne which($0)) {
51    # -[hCV] are not handled; they will have already been handled earlier.
52    push(@script, "-d") if $opt_d;
53    push(@script, "-l") if $opt_l;
54    push(@script, "-f") if $opt_f;
55    push(@script, $host);
56    if ($debug) {
57	print(STDERR "device script ($script[0]) does not appear to be me ($0)".
58		     ": exec(".  join(" ", @script) .")\n");
59    }
60    # there is no way to prevent an error msg from exec such that the die error
61    # is the only one displayed, without also leaving the child without a
62    # working STDERR.
63    exec(join(" ", @script)) || die "exec($script[0]) failed: $!\n";
64}
65
66# check that inloop, the input/main loop, is defined
67if (!defined($inloop) || length($inloop) < 1) {
68    die "inloop is not configured for device type $devtype";
69}
70
71# open the temporary file for the digested output
72open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
73select(OUTPUT);
74if (length($#modules)) {
75    my($module);
76
77    foreach $module (@modules) {
78	(my $file = $module) =~ s/::/\//g;
79	my($err) = 0;
80
81	# call module->init(); we expect 0 as success, as god intended it
82	eval "\$err = ". $module ."::init();";
83	if ($@) {
84	    printf(STDERR "loadtype: initializing $module failed: %s\n", $@);
85	    exit 1;
86	} elsif ($err) {
87	    printf(STDERR "loadtype: %s::init() returned failure\n", $module);
88	    exit 1;
89	}
90    }
91}
92
93# open the input; a pre-collected file or start a login for a login stream or
94# temporary file
95if ($file) {
96    print(STDERR "opening file $host\n") if ($debug || $log);
97    open(INPUT,"<$host") || die "open failed for $host: $!\n";
98} else {
99    my $cstr = $commandstr;
100    $cstr =~ s/\"/\\\"/g;
101    print(STDERR "executing $lscript -t $timeo -c\"$cstr\" $host\n") if ($debug || $log);
102    system "$lscript -t $timeo -c \"$cstr\" $host </dev/null > $host.raw 2>&1" || die "clogin failed for $host: $!\n";
103    open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n";
104}
105
106# loop over the input using the provided input/main loop
107eval($inloop ."(*INPUT, *OUTPUT);") && die "${inloop} failed: $@\n";
108
109print STDOUT "Done $lscript: $_\n" if ($log);
110# Flush History
111ProcessHistory("","","","");
112# Cleanup
113close(INPUT);
114close(OUTPUT);
115
116unlink("$host.raw") if (! $debug);
117
118# check for completeness
119if (scalar(%commands) || !$clean_run || !$found_end) {
120    if (scalar(keys %commands) eq $commandcnt) {
121	printf(STDERR "$host: missed cmd(s): all commands\n");
122    } elsif (scalar(%commands)) {
123	my($count, $i) = 0;
124	for ($i = 0; $i < $#commands; $i++) {
125	    if ($commands{$commands[$i]}) {
126		if (!$count) {
127		    printf(STDERR "$host: missed cmd(s): %s", $commands[$i]);
128		} else {
129		    printf(STDERR ", %s", $commands[$i]);
130		}
131		$count++;
132	    }
133	}
134	if ($count) {
135	    printf(STDERR "\n");
136	}
137    }
138    if (!$clean_run || !$found_end) {
139	print(STDERR "$host: End of run not found\n");
140	if ($debug) {
141	    print(STDERR "$host: clean_run is false\n") if (!$clean_run);
142	    print(STDERR "$host: found_end is false\n") if (!$found_end);
143	}
144	system("/usr/bin/tail -1 $host.new");
145    }
146    unlink "$host.new" if (! $debug);
147}
148