Annotation of trango/Net-Telnet-Trango/scripts/update_trango.pl, Revision 1.18
1.16 mike 1: #!/usr/bin/perl
1.18 ! mike 2: # $RedRiver: update_trango.pl,v 1.17 2007/01/31 18:44:27 mike Exp $
1.16 mike 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::TFTP;
12: use lib '.';
13: use Net::Telnet::Trango;
14:
15: my $config_file = shift || 'update_trango.conf';
16: my $max_tries = 3;
17:
18:
19:
20: my $l = Mylogger->new( { log_prefix => 'UT' } );
21:
22:
23: $l->sp("Reading config file '$config_file'");
24: my $conf = read_conf($config_file);
25:
26: $l->sp(" Hardware Type: $conf->{'type'}");
27: $l->sp(" File Name: $conf->{'file_name'}");
28: $l->sp(" File Size: $conf->{'file_size'}");
29: $l->sp(" File Checksum: $conf->{'file_cksum'}");
30: $l->sp(" FW Version: $conf->{'ver'}");
31: $l->sp(" FW Checksum: $conf->{'cksum'}");
32: $l->sp("");
33:
34:
35:
36:
37:
38:
39: foreach my $fox (@{ $conf->{'ips'} }) {
40: $l->sp("Updating: $fox");
41:
42: ## Connect and login.
43: my $t = new Net::Telnet::Trango (
44: Timeout => 5,
45: Errmode => 'return',
46: ) or die "Couldn't make new connection: $!";
47: $l->p("Connecting to $fox");
48: unless ( $t->open($fox) ) {
49: $l->sp("Error connecting: $!");
50: next;
51: }
52:
53: if ($t->host_type ne $conf->{'type'}) {
1.17 mike 54: $l->sp("Wrong type of unit ('" . $t->host_type . "' should be '$conf->{'type'}')");
1.16 mike 55: $t->close;
56: next;
57: }
58:
59: if ($t->firmware_version eq $conf->{'ver'}) {
1.18 ! mike 60: $l->sp("Already up to date with firmware version '" . $t->firmware_version . "'");
1.16 mike 61: $t->close;
62: next;
63: }
64:
65: $l->p("Logging in");
66: $t->login($conf->{'password'}) || die "Couldn't login: $!";
67:
68: $l->p("Sending commands");
69: ## Send commands
1.17 mike 70: if ( upload($t, $conf->{'file_name'}) ) {
71: $l->p("Rebooting");
72: $t->reboot;
73: } else {
1.16 mike 74: $l->p("Exiting");
75: $t->exit;
1.17 mike 76: }
1.16 mike 77:
78: $l->sp("");
79: }
80:
81: sub upload
82: {
83: my $t = shift;
84: my $file = shift;
85:
86: my $ver = $t->ver;
87: $l->p("Current version '$ver->{'Firmware Version'}'");
88:
89: if (
90: $ver->{'Firmware Version'} eq $conf->{'ver'} &&
91: $ver->{'Firmware Checksum'} eq $conf->{'cksum'}
92: ) {
93: $l->sp("Already updated!");
94: return 1;
95: }
96:
97: my $try = 0;
98: while (1) {
99: if ($try >= $max_tries) {
100: $l->sp("Couldn't update in $max_tries tries!");
101: return undef;
102: }
103: $try++;
104:
105: #sysinfo($self->{'_host'});
106:
107: $l->p("Enabling TFTPd");
108: $t->enable_tftpd || die "Couldn't enable tftpd";
109:
110: $l->p("Uploading file ($file)");
111: # use tftp to push the file up
112: my $tftp = Net::TFTP->new($t->Host, Mode => 'octet');
113:
114: $tftp->put($file, $file)
115: or die "Error uploading: " . $tftp->error;
116:
117: # waitfor some sort of output
118: # make sure it says 'Success.' otherwise error
119: #print "LAST: " . $self->lastline;
120: #my @lines = $self->getlines;
121: #print Dump \@lines;
122:
123: $l->p("Checking upload ($conf->{'file_cksum'})");
124: my $results = $t->tftpd;
125: # check the 'File Length' against ???
126: if ( $results->{'File Checksum'} ne $conf->{'file_cksum'}) {
127: $l->sp(
128: "File checksum '" . $results->{'File Checksum'} .
129: "does not match config file '" . $conf->{'file_cksum'} . "'!"
130: );
131: next;
132: }
133: $l->p("File checksum matches . . . ");
134:
135: if ($results->{'File Length'} !~ /^$conf->{'file_size'} bytes/) {
136: $l->sp(
137: "File length '" . $results->{'File Length'} .
138: "does not match config file '" . $conf->{'file_size'} . " bytes'!"
139: );
140: next;
141: }
142: $l->p("File length matches . . . ");
143:
144: if ( uc($results->{'File Name'}) ne uc($conf->{'file_name'}) ) {
145: $l->sp(
146: "File name '" . $results->{'File Name'} .
147: "' does not match config file '" . $conf->{'file_name'} . "'!"
148: );
149: next;
150: }
151: $l->p("File name matches . . . ");
152:
153: $l->p("Updating flash (new checksum '$conf->{'cksum'}')");
154: unless ($results = $t->updateflash(
155: args => 'mainimage ' . $ver->{'Firmware Checksum'} .
156: ' ' . $conf->{'cksum'},
157: Timeout => 90,
158: ) ) {
159: $l->sp("Couldn't update flash: $!");
160: next;
161: }
162:
163: unless (
164: defined $results->{'Checksum'} &&
165: $results->{'Checksum'} eq $conf->{'cksum'}
166: ) {
1.17 mike 167: $l->sp("Saved checksum " . $results->{'Checksum'} . " does not match config file " . $conf->{'cksum'} . "!");
1.16 mike 168: next;
169: }
170: $l->p("Uploaded checksum ($results->{'Checksum'}) " .
171: "matches ($conf->{'cksum'})");
172:
173: $l->sp("Successfully updated!");
174: return 1;
175: }
176: }
177:
178: sub read_conf
179: {
180: my $file = shift;
181: my %conf;
182: my $in_ip_list = 0;
183: open my $fh, $file or die "Couldn't open file $file: $!";
184: while (<$fh>) {
185: chomp;
186: next if /^#/;
187: next if /^$/;
188: if ($in_ip_list) {
189: s/\s+//g; # Whitespace is a no no
190:
191: if (/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.)(\d{1,3})-(\d{1,3})/) {
192: push @{ $conf{'ips'} }, $1 . $_ for ($2..$3);
193: } else {
194: push @{ $conf{'ips'} }, $_;
195: }
196: } else {
197: my ($key, $val) = split /\s+/, $_, 2;
198:
199: if (lc($key) eq 'ips') {
200: $in_ip_list = 1;
201: next;
202: }
203:
204: $key =~ s/^\s+//;
205: $key =~ s/\s+$//;
206: $val =~ s/^\s+//;
207: $val =~ s/\s+$//;
208:
209: $conf{ lc($key) } = $val;
210: }
211: }
212: close $fh;
213:
214: #print Dump \%conf;
215: foreach (
216: 'password',
217: 'file_name', 'file_size', 'file_cksum',
218: 'ver', 'cksum', 'ips',
219: ) {
220: die "No $_ specified in config file!"
221: if (not exists $conf{$_});
222: }
223:
224: #print Dump \%conf;
225: #exit;
226: return \%conf;
227: }
228:
229: package Mylogger;
230:
231: use Fcntl ':flock'; # import LOCK_* constants
232: #use YAML;
233: use constant LOG_PRINT => 128;
234: use constant LOG_SAVE => 64;
235:
236: DESTROY {
237: my $self = shift;
238: if ($self->{'MYLOG'}) {
239: $self->p("Closing log ($self->{'log_path'}/$self->{'log_file'})");
240: close $self->{'MYLOG'};
241: }
242: }
243:
244: sub new {
245: my $package = shift;
246: my $self = shift || {};
247:
248: $self->{'base_path'} ||= '.';
249: $self->{'log_path'} ||= $self->{'base_path'};
250: $self->{'log_prefix'} ||= 'LOG';
251: $self->{'log_file'} ||= GetLogName(
252: $self->{'log_prefix'},
253: $self->{'log_path'}
254: );
255: bless $self, $package;
256: }
257:
258: sub s
259: {
260: my $self = shift;
261: my $m = shift;
262: return $self->mylog($m, LOG_SAVE);
263: }
264:
265: sub p
266: {
267: my $self = shift;
268: my $m = shift;
269: return $self->mylog($m, LOG_PRINT);
270: }
271:
272: sub sp
273: {
274: my $self = shift;
275: my $m = shift;
276: return $self->mylog($m, LOG_SAVE | LOG_PRINT);
277: }
278:
279: sub mylog
280: {
281: my $self = shift;
282:
283: my $thing = shift;
284: chomp $thing;
285:
286: my $which = shift;
287:
288: my $MYLOG;
289: if ($which & LOG_PRINT) {
290: print $thing, "\n";
291: }
292:
293: if ($which & LOG_SAVE) {
294: if ($self->{'MYLOG'}) {
295: $MYLOG = $self->{'MYLOG'};
296: } else {
297: unless ($MYLOG) {
298: open ($MYLOG, '>>', $self->{'log_path'} . '/' . $self->{'log_file'})
299: or die "Couldn't open logfile!\n";
300: my $ofh = select $MYLOG;
301: $|=1;
302: select $ofh;
303: $self->{'MYLOG'} = $MYLOG;
304:
305: $self->p("Opened log ($self->{'log_path'}/$self->{'log_file'})");
306: }
307: }
308: flock($MYLOG, LOCK_EX);
309: print $MYLOG (scalar gmtime), "\t", $thing, "\n"
310: or die "Couldn't print to MYLOG: $!";
311: flock($MYLOG, LOCK_UN);
312: }
313: }
314:
315: sub GetLogName
316: {
317: my $prefix = shift || die "Invalid prefix passed for log";
318:
319: my $logdate = GetLogDate();
320: my $logver = 0;
321: my $logname;
322:
323: do {
324: $logname = $prefix . $logdate . sprintf("%02d", $logver) . '.log';
325: $logver++;
326: } until (not -e $logname);
327:
328: return $logname;
329: }
330:
331: sub GetLogDate
332: {
333: my ($sec,$min,$hour,$mday,$mon,$year,,,) = localtime();
334:
335: $mon++;
336: $year += 1900;
337:
338: if ($min < 10) { $min = "0$min" }
339: if ($sec < 10) { $sec = "0$sec" }
340: if ($hour < 10) { $hour = "0$hour" }
341: if ($mday < 10) { $mday = "0$mday" }
342: if ($mon < 10) { $mon = "0$mon" }
343:
344: my $time = $year . $mon . $mday;
345:
346: return $time;
347: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>