Annotation of trango/Net-Telnet-Trango/scripts/update_trango.pl, Revision 1.3
1.1 andrew 1: #!/usr/bin/perl
1.3 ! andrew 2: # $RedRiver: update_trango.pl,v 1.2 2005/11/16 05:26:37 andrew Exp $
1.1 andrew 3: ########################################################################
4: # update_trango.pl *** Updates trango foxes with a new firmware
5: #
6: # 2005.11.15 #*#*# andrew fresh <andrew@mad-techies.org>
7: ########################################################################
8: use strict;
9: use warnings;
10:
11: use Net::Telnet;
1.2 andrew 12: use Net::TFTP;
1.3 ! andrew 13: #use YAML;
1.2 andrew 14:
15:
1.3 ! andrew 16: my $config_file = shift || 'fox53.conf';
! 17: my $conf = read_conf($config_file);
1.2 andrew 18:
1.3 ! andrew 19: my $max_tries = 1;
1.2 andrew 20:
21:
22:
23:
24:
25:
1.3 ! andrew 26: foreach my $fox (@{ $conf->{'ips'} }) {
! 27: print STDERR "Updating: $fox\n";
1.2 andrew 28:
29: ## Connect and login.
30: my $host = new Net::Telnet (Timeout => 5,
31: Prompt => '/#> *$/');
1.3 ! andrew 32: print "Connecting to $fox\n";
1.2 andrew 33: $host->open($fox);
34: $host->dump_log('dump.log');
35:
36: ## Login to remote host.
37: $host->waitfor(
38: -match => '/password: ?$/i',
39: -errmode => "return",
40: ) or die "problem connecting to host ($fox): ", $host->lastline;
1.3 ! andrew 41:
! 42: my $login_banner = $host->lastline;
! 43: my ($type, $version) = $login_banner =~
! 44: /Welcome to Trango Broadband Wireless (\w+)-(.+)$/i;
! 45:
! 46: if ($type ne $conf->{'type'}) {
! 47: print STDERR "Wrong type of unit ('$type' should be '$conf->{'type'}')\n";
! 48: $host->close;
! 49: next;
! 50: }
! 51:
! 52: if ($version eq $conf->{'ver'}) {
! 53: print STDERR "Already up to date with firmware version '$version'\n";
! 54: $host->close;
! 55: next;
! 56: }
! 57:
! 58: print "Logging in\n";
! 59: $host->print($conf->{'password'});
1.2 andrew 60: $host->waitfor(
61: -match => $host->prompt,
62: -errmode => "return",
63: ) or die "login ($fox) failed: ", $host->lastline;
64:
1.3 ! andrew 65:
! 66: print "Sending commands\n";
1.2 andrew 67: ## Send commands
1.3 ! andrew 68: if ( upload($host, $fox, $conf->{'file_name'}) ) {
! 69: print "Rebooting\n";
! 70: $host->print("reboot\n");
! 71: $host->getline;
1.2 andrew 72: } else {
1.3 ! andrew 73: print "Exiting\n";
! 74: $host->print("exit\n");
! 75: $host->getline;
1.2 andrew 76: }
77: $host->close;
78: }
79:
80: sub upload
81: {
82: my $host = shift;
1.3 ! andrew 83: my $fox = shift;
1.2 andrew 84: my $file = shift;
1.3 ! andrew 85:
! 86: print "Getting current version\n";
1.2 andrew 87: my $ver = get_ver($host);
88:
89: if (
1.3 ! andrew 90: $ver->{'Firmware Version'} eq $conf->{'ver'} &&
! 91: $ver->{'Firmware Checksum'} eq $conf->{'cksum'}
1.2 andrew 92: ) {
1.3 ! andrew 93: print STDERR "Already updated!";
1.2 andrew 94: return 1;
95: }
96:
97: my $try = 0;
98: while (1) {
1.3 ! andrew 99: if ($try >= $max_tries) {
! 100: print STDERR "Couldn't update in $max_tries tries!";
! 101: return undef;
! 102: }
1.2 andrew 103: $try++;
104:
1.3 ! andrew 105: #sysinfo($host);
! 106:
! 107: print "Enabling TFTPd\n";
1.2 andrew 108: enable_tftpd($host) || die "Couldn't enable tftpd";
109:
1.3 ! andrew 110: print "Uploading file\n";
1.2 andrew 111: # use tftp to push the file up
1.3 ! andrew 112: my $tftp = Net::TFTP->new($fox, Mode => 'octet');
! 113:
! 114: $tftp->put($file, $file)
! 115: or die "Error uploading: " . $tftp->error;
1.2 andrew 116:
117: # waitfor some sort of output
118: # make sure it says 'Success.' otherwise error
1.3 ! andrew 119: #print "LAST: " . $host->lastline;
! 120: #my @lines = $host->getlines;
! 121: #print Dump \@lines;
1.2 andrew 122:
1.3 ! andrew 123: print "Checking upload\n";
1.2 andrew 124: my $results = check_tftpd($host);
125: # check the 'File Length' against ???
1.3 ! andrew 126: if ( $results->{'File Checksum'} ne $conf->{'file_cksum'}) {
! 127: print STDERR "File checksum does not match config file!";
! 128: next;
! 129: }
! 130:
! 131: if ($results->{'File Length'} !~ /^$conf->{'file_size'} bytes/) {
! 132: print STDERR "File length does not match config file!";
! 133: next;
! 134: }
1.2 andrew 135:
1.3 ! andrew 136: if ( uc($results->{'File Name'}) ne uc($conf->{'file_name'}) ) {
! 137: print STDERR "File name does not match config file!";
! 138: next;
! 139: }
1.2 andrew 140:
1.3 ! andrew 141: print "Updating flash\n";
! 142: $results = updateflash(
! 143: $host, $ver->{'Firmware Checksum'}, $conf->{'cksum'}
! 144: ) or die "Couldn't update flash: " . $host->lastline;
! 145: unless (
! 146: defined $results->{'Checksum'} &&
! 147: $results->{'Checksum'} eq $conf->{'cksum'}
! 148: ) {
! 149: print STDERR "Saved checksum does not match config file!";
! 150: next;
1.2 andrew 151: }
1.3 ! andrew 152:
! 153: print STDERR "Successfully updated!\n";
! 154: return 1;
1.2 andrew 155: }
156: }
157:
158: sub get_ver
159: {
160: my $host = shift;
161: return cmd($host, 'ver');
162: }
163:
164: sub enable_tftpd
165: {
166: my $host = shift;
167:
1.3 ! andrew 168: my $vals = cmd($host, 'tftpd on', 'Success.');
1.2 andrew 169:
170: if ($vals->{'Tftpd'} eq 'listen') {
1.3 ! andrew 171: return $vals;
1.2 andrew 172: } else {
173: return undef;
174: }
175: }
176:
177: sub check_tftpd
178: {
179: my $host = shift;
1.3 ! andrew 180: return cmd($host, 'tftpd', 'Success.');
! 181: }
! 182:
! 183: sub sysinfo
! 184: {
! 185: my $host = shift;
! 186: return cmd($host, 'sysinfo', 'Success.');
! 187: }
! 188:
! 189: sub updateflash
! 190: {
! 191: my $host = shift;
! 192: my $old = shift;
! 193: my $new = shift;
! 194:
! 195: return undef unless $new;
! 196:
! 197: return cmd($host, "updateflash mainimage $old $new", 'Success.', 90);
1.2 andrew 198: }
199:
200: sub cmd
201: {
202: my $host = shift;
203: my $string = shift;
1.3 ! andrew 204: my $expect_last = shift;
! 205: my $timeout = shift || 5;
1.2 andrew 206:
1.3 ! andrew 207: my @lines = $host->cmd(String => $string, Timeout => $timeout);
1.2 andrew 208:
209: my $vals = decode_lines(@lines);
1.3 ! andrew 210:
! 211: my $last = $host->lastline;
! 212:
! 213: unless ($expect_last) {
! 214: return $vals;
! 215: }
! 216:
! 217: if ($last =~ /$expect_last$/) {
! 218: return $vals;
! 219: } else {
! 220: warn "Error with command ($string): $last";
! 221: return undef;
! 222: }
1.2 andrew 223: }
224:
225: sub decode_lines
226: {
227: my @lines = @_;
228:
229: my %conf;
230:
231: my $key = '';
232: my $val = '';
233: my $in_key = 0;
234: my $in_val = 0;
235:
236: foreach my $line (@lines) {
237: my @chars = split //, $line;
238:
1.3 ! andrew 239: my $last_key = '';
1.2 andrew 240: foreach my $c (@chars) {
241:
1.3 ! andrew 242: if ($c eq '[' || $c eq "\r" || $c eq "\n") {
! 243: if ($c eq '[') {
! 244: $in_key = 1;
! 245: $in_val = 0;
! 246: } else {
! 247: $in_key = 0;
! 248: $in_val = 0;
! 249: }
! 250:
1.2 andrew 251: if ($key) {
1.3 ! andrew 252: $key =~ s/^\s+//;
! 253: $key =~ s/\s+$//;
! 254:
! 255: $val =~ s/^\s+//;
1.2 andrew 256: $val =~ s/\s+$//;
1.3 ! andrew 257:
! 258: if ($key eq 'Checksum' && $last_key) {
! 259: # Special case for these bastids.
! 260: my $new = $last_key;
! 261: $new =~ s/\s+\S+$//;
! 262: $key = $new . " " . $key;
! 263: }
! 264:
! 265: $last_key = $key;
1.2 andrew 266: $conf{$key} = $val;
267: $key = '';
268: $val = '';
269: }
270:
271: } elsif ($c eq ']') {
272: $in_val = 1;
273: $in_key = 0;
274: $c = shift @chars;
275:
276: } elsif ($in_key) {
277: $key .= $c;
278:
279: } elsif ($in_val) {
280: $val .= $c;
281: }
282: }
283: }
1.3 ! andrew 284: #print Dump \%conf;
1.2 andrew 285:
286: if (%conf) {
287: return \%conf;
288: } else {
289: return \@lines;
290: }
291: }
1.1 andrew 292:
1.3 ! andrew 293: sub read_conf
! 294: {
! 295: my $file = shift;
! 296: my %conf;
! 297: my $in_ip_list = 0;
! 298: open my $fh, $file or die "Couldn't open file $file: $!";
! 299: while (<$fh>) {
! 300: chomp;
! 301: next if /^#/;
! 302: next if /^$/;
! 303: if ($in_ip_list) {
! 304: push @{ $conf{'ips'} }, $_;
! 305: } else {
! 306: my ($key, $val) = split /\s+/, $_, 2;
! 307:
! 308: if (lc($key) eq 'ips') {
! 309: $in_ip_list = 1;
! 310: next;
! 311: }
! 312:
! 313: $conf{ lc($key) } = $val;
! 314: }
! 315: }
! 316: close $fh;
! 317:
! 318: #print Dump \%conf;
! 319: foreach (
! 320: 'password',
! 321: 'file_name', 'file_size', 'file_cksum',
! 322: 'ver', 'cksum', 'ips',
! 323: ) {
! 324: die "No $_ specified in config file!"
! 325: if (not exists $conf{$_});
! 326: }
! 327:
! 328: return \%conf;
! 329: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>