[BACK]Return to update_trango.pl CVS log [TXT][DIR] Up to [local] / trango / Net-Telnet-Trango / scripts

Annotation of trango/Net-Telnet-Trango/scripts/update_trango.pl, Revision 1.4

1.1       andrew      1: #!/usr/bin/perl
1.4     ! andrew      2: # $RedRiver: update_trango.pl,v 1.3 2005/11/16 20:48:48 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.4     ! andrew     13: use Fcntl ':flock'; # import LOCK_* constants
1.3       andrew     14: #use YAML;
1.2       andrew     15: 
                     16: 
1.4     ! andrew     17: my $config_file = shift || 'update_trango.conf';
1.3       andrew     18: my $conf = read_conf($config_file);
1.2       andrew     19: 
1.3       andrew     20: my $max_tries = 1;
1.2       andrew     21: 
1.4     ! andrew     22: my $log_file =  GetLogName('UT');
        !            23: 
        !            24: 
        !            25: my $MYLOG;  # file handle for logging so we don't have to close and open it all the time
        !            26: END {
        !            27:   if ($MYLOG) {
        !            28:     mylog("Closing log ($log_file)");
        !            29:     close $MYLOG;
        !            30:   }
        !            31: }
        !            32: 
        !            33: 
        !            34: 
1.2       andrew     35: 
                     36: 
                     37: 
                     38: 
                     39: 
1.3       andrew     40: foreach my $fox (@{ $conf->{'ips'} }) {
1.4     ! andrew     41:   mylog("Updating: $fox");
1.2       andrew     42: 
                     43:   ## Connect and login.
                     44:   my $host = new Net::Telnet (Timeout => 5,
                     45:                               Prompt => '/#> *$/');
1.4     ! andrew     46:   mylog("Connecting to $fox");
1.2       andrew     47:   $host->open($fox);
                     48:   $host->dump_log('dump.log');
                     49: 
                     50:   ## Login to remote host.
                     51:   $host->waitfor(
                     52:     -match => '/password: ?$/i',
                     53:     -errmode => "return",
                     54:   ) or die "problem connecting to host ($fox): ", $host->lastline;
1.3       andrew     55: 
                     56:   my $login_banner = $host->lastline;
                     57:   my ($type, $version) = $login_banner =~ 
                     58:     /Welcome to Trango Broadband Wireless (\w+)-(.+)$/i;
                     59: 
                     60:   if ($type ne $conf->{'type'}) {
1.4     ! andrew     61:     mylog("Wrong type of unit ('$type' should be '$conf->{'type'}')");
1.3       andrew     62:     $host->close;
                     63:     next;
                     64:   }
                     65: 
                     66:   if ($version eq $conf->{'ver'}) {
1.4     ! andrew     67:     mylog("Already up to date with firmware version '$version'");
1.3       andrew     68:     $host->close;
                     69:     next;
                     70:   }
                     71: 
1.4     ! andrew     72:   mylog("Logging in");
1.3       andrew     73:   $host->print($conf->{'password'});
1.2       andrew     74:   $host->waitfor(
                     75:     -match => $host->prompt,
                     76:     -errmode => "return",
                     77:   ) or die "login ($fox) failed: ", $host->lastline;
                     78: 
1.3       andrew     79: 
1.4     ! andrew     80:   mylog("Sending commands");
1.2       andrew     81:   ## Send commands
1.3       andrew     82:   if ( upload($host, $fox, $conf->{'file_name'}) ) {
1.4     ! andrew     83:     mylog("Rebooting");
1.3       andrew     84:     $host->print("reboot\n");
                     85:     $host->getline;
1.2       andrew     86:   } else {
1.4     ! andrew     87:     mylog("Exiting");
1.3       andrew     88:     $host->print("exit\n");
                     89:     $host->getline;
1.2       andrew     90:   }
                     91:   $host->close;
1.4     ! andrew     92:   mylog("");
1.2       andrew     93: }
                     94: 
                     95: sub upload
                     96: {
                     97:   my $host = shift;
1.3       andrew     98:   my $fox  = shift;
1.2       andrew     99:   my $file = shift;
1.3       andrew    100: 
1.4     ! andrew    101:   mylog("Getting current version");
1.2       andrew    102:   my $ver = get_ver($host);
                    103: 
                    104:   if (
1.3       andrew    105:     $ver->{'Firmware Version'}  eq $conf->{'ver'} && 
                    106:     $ver->{'Firmware Checksum'} eq $conf->{'cksum'}
1.2       andrew    107:   ) {
1.4     ! andrew    108:     mylog("Already updated!");
1.2       andrew    109:     return 1;
                    110:   }
                    111: 
                    112:   my $try = 0;
                    113:   while (1) {
1.3       andrew    114:     if ($try >= $max_tries) {
1.4     ! andrew    115:       mylog("Couldn't update in $max_tries tries!");
1.3       andrew    116:       return undef;
                    117:     }
1.2       andrew    118:     $try++;
                    119: 
1.3       andrew    120:     #sysinfo($host);
                    121:     
1.4     ! andrew    122:     mylog("Enabling TFTPd");
1.2       andrew    123:     enable_tftpd($host) || die "Couldn't enable tftpd";
                    124: 
1.4     ! andrew    125:     mylog("Uploading file");
1.2       andrew    126:     # use tftp to push the file up
1.3       andrew    127:     my $tftp = Net::TFTP->new($fox, Mode => 'octet');
                    128: 
                    129:     $tftp->put($file, $file) 
                    130:       or die "Error uploading: " . $tftp->error;
1.2       andrew    131: 
                    132:     # waitfor some sort of output
                    133:     # make sure it says 'Success.' otherwise error
1.3       andrew    134:     #print "LAST: " . $host->lastline;
                    135:     #my @lines = $host->getlines;
                    136:     #print Dump \@lines;
1.2       andrew    137:     
1.4     ! andrew    138:     mylog("Checking upload");
1.2       andrew    139:     my $results = check_tftpd($host);
                    140:     # check the 'File Length' against ???
1.3       andrew    141:     if ( $results->{'File Checksum'} ne $conf->{'file_cksum'}) {
1.4     ! andrew    142:       mylog("File checksum does not match config file!");
1.3       andrew    143:       next;
                    144:     }
                    145: 
                    146:     if ($results->{'File Length'}   !~ /^$conf->{'file_size'} bytes/) {
1.4     ! andrew    147:       mylog("File length does not match config file!");
1.3       andrew    148:       next;
                    149:     }
1.2       andrew    150: 
1.3       andrew    151:     if ( uc($results->{'File Name'}) ne uc($conf->{'file_name'}) ) {
1.4     ! andrew    152:       mylog("File name does not match config file!");
1.3       andrew    153:       next;
                    154:     }
1.2       andrew    155: 
1.4     ! andrew    156:     mylog("Updating flash");
1.3       andrew    157:     $results = updateflash(
                    158:       $host, $ver->{'Firmware Checksum'}, $conf->{'cksum'}
                    159:     ) or die "Couldn't update flash: " . $host->lastline;
                    160:     unless (
                    161:       defined $results->{'Checksum'} && 
                    162:       $results->{'Checksum'} eq $conf->{'cksum'}
                    163:     ) {
1.4     ! andrew    164:       mylog("Saved checksum does not match config file!");
1.3       andrew    165:       next;
1.2       andrew    166:     }
1.3       andrew    167:     
1.4     ! andrew    168:     mylog("Successfully updated!");
1.3       andrew    169:     return 1;
1.2       andrew    170:   }
                    171: }
                    172: 
                    173: sub get_ver
                    174: {
                    175:   my $host = shift;
                    176:   return cmd($host, 'ver');
                    177: }
                    178: 
                    179: sub enable_tftpd
                    180: {
                    181:   my $host = shift;
                    182: 
1.3       andrew    183:   my $vals = cmd($host, 'tftpd on', 'Success.');
1.2       andrew    184: 
                    185:   if ($vals->{'Tftpd'} eq 'listen') {
1.3       andrew    186:     return $vals;
1.2       andrew    187:   } else {
                    188:     return undef;
                    189:   }
                    190: }
                    191: 
                    192: sub check_tftpd
                    193: {
                    194:   my $host = shift;
1.3       andrew    195:   return cmd($host, 'tftpd', 'Success.');
                    196: }
                    197: 
                    198: sub sysinfo
                    199: {
                    200:   my $host = shift;
                    201:   return cmd($host, 'sysinfo', 'Success.');
                    202: }
                    203: 
                    204: sub updateflash
                    205: {
                    206:   my $host = shift;
                    207:   my $old = shift;
                    208:   my $new = shift;
                    209: 
                    210:   return undef unless $new;
                    211: 
                    212:   return cmd($host, "updateflash mainimage $old $new", 'Success.', 90);
1.2       andrew    213: }
                    214: 
                    215: sub cmd
                    216: {
                    217:   my $host   = shift;
                    218:   my $string = shift;
1.3       andrew    219:   my $expect_last = shift;
                    220:   my $timeout = shift || 5;
1.2       andrew    221: 
1.3       andrew    222:   my @lines = $host->cmd(String => $string, Timeout => $timeout);
1.2       andrew    223: 
                    224:   my $vals = decode_lines(@lines);
1.3       andrew    225: 
                    226:   my $last = $host->lastline;
                    227: 
                    228:   unless ($expect_last) {
                    229:     return $vals;
                    230:   }
                    231: 
                    232:   if ($last =~ /$expect_last$/) {
                    233:     return $vals;
                    234:   } else {
                    235:     warn "Error with command ($string): $last";
                    236:     return undef;
                    237:   }
1.2       andrew    238: }
                    239: 
                    240: sub decode_lines
                    241: {
                    242:   my @lines = @_;
                    243: 
                    244:   my %conf;
                    245: 
                    246:   my $key = '';
                    247:   my $val = '';
                    248:   my $in_key = 0;
                    249:   my $in_val = 0;
                    250: 
                    251:   foreach my $line (@lines) {
                    252:     my @chars = split //, $line;
                    253: 
1.3       andrew    254:     my $last_key = '';
1.2       andrew    255:     foreach my $c (@chars) {
                    256: 
1.3       andrew    257:       if ($c eq '[' || $c eq "\r" || $c eq "\n") {
                    258:         if ($c eq '[') {
                    259:           $in_key = 1;
                    260:           $in_val = 0;
                    261:         } else {
                    262:           $in_key = 0;
                    263:           $in_val = 0;
                    264:         }
                    265: 
1.2       andrew    266:         if ($key) {
1.3       andrew    267:           $key =~ s/^\s+//;
                    268:           $key =~ s/\s+$//;
                    269: 
                    270:           $val =~ s/^\s+//;
1.2       andrew    271:           $val =~ s/\s+$//;
1.3       andrew    272: 
                    273:           if ($key eq 'Checksum' && $last_key) {
                    274:             # Special case for these bastids.
                    275:             my $new = $last_key;
                    276:             $new =~ s/\s+\S+$//;
                    277:             $key = $new . " " . $key;
                    278:           }
                    279: 
                    280:           $last_key = $key;
1.2       andrew    281:           $conf{$key} = $val;
                    282:           $key = '';
                    283:           $val = '';
                    284:         }
                    285: 
                    286:       } elsif ($c eq ']') {
                    287:         $in_val = 1;
                    288:         $in_key = 0;
                    289:         $c = shift @chars;
                    290: 
                    291:       } elsif ($in_key) {
                    292:         $key .= $c;
                    293: 
                    294:       } elsif ($in_val) {
                    295:         $val .= $c;
                    296:       }
                    297:     }
                    298:   }
1.3       andrew    299:   #print Dump \%conf;
1.2       andrew    300: 
                    301:   if (%conf) {
                    302:     return \%conf;
                    303:   } else {
                    304:     return \@lines;
                    305:   }
                    306: }
1.1       andrew    307: 
1.3       andrew    308: sub read_conf
                    309: {
                    310:   my $file = shift;
                    311:   my %conf;
                    312:   my $in_ip_list = 0;
                    313:   open my $fh, $file or die "Couldn't open file $file: $!";
                    314:   while (<$fh>) {
                    315:     chomp;
                    316:     next if /^#/;
                    317:     next if /^$/;
                    318:     if ($in_ip_list) {
                    319:       push @{ $conf{'ips'} }, $_;
                    320:     } else {
                    321:       my ($key, $val) = split /\s+/, $_, 2;
                    322: 
                    323:       if (lc($key) eq 'ips') {
                    324:         $in_ip_list = 1;
                    325:         next;
                    326:       }
                    327: 
                    328:       $conf{ lc($key) } = $val;
                    329:     }
                    330:   }
                    331:   close $fh;
                    332: 
                    333:   #print Dump \%conf;
                    334:   foreach (
                    335:     'password', 
                    336:     'file_name', 'file_size', 'file_cksum', 
                    337:     'ver', 'cksum', 'ips',
                    338:   ) {
                    339:     die "No $_ specified in config file!"
                    340:       if (not exists $conf{$_});
                    341:   }
                    342: 
                    343:   return \%conf;
1.4     ! andrew    344: }
        !           345: 
        !           346: sub mylog
        !           347: {
        !           348:        my $thing = shift;
        !           349:     chomp $thing;
        !           350: 
        !           351:        unless ($MYLOG) {
        !           352:                open ($MYLOG, '>>', $log_file) 
        !           353:                        or die "Couldn't open logfile!\n";
        !           354:                my $ofh = select $MYLOG;
        !           355:                $|=1;
        !           356:                select $ofh;
        !           357:         mylog("Opened log ($log_file)");
        !           358:        }
        !           359: 
        !           360:     print $thing, "\n";
        !           361:        flock($MYLOG, LOCK_EX);
        !           362:        print $MYLOG (scalar gmtime), "\t", $thing, "\n" 
        !           363:                or die "Couldn't print to MYLOG: $!";
        !           364:        flock($MYLOG, LOCK_UN);
        !           365: }
        !           366: 
        !           367: sub GetLogName
        !           368: {
        !           369:   my $prefix  = shift || die "Invalid prefix passed for log";
        !           370: 
        !           371:   my $logdate = GetLogDate();
        !           372:   my $logver  = 0;
        !           373:   my $logname;
        !           374: 
        !           375:   do {
        !           376:     $logname = $prefix . $logdate . sprintf("%02d", $logver) . '.log';
        !           377:     $logver++;
        !           378:   } until (not -e $logname);
        !           379: 
        !           380:   return $logname;
        !           381: }
        !           382: 
        !           383: sub GetLogDate
        !           384: {
        !           385:   my ($sec,$min,$hour,$mday,$mon,$year,,,) = localtime();
        !           386: 
        !           387:   $mon++;
        !           388:   $year += 1900;
        !           389: 
        !           390:   if ($min  < 10) { $min  = "0$min"  }
        !           391:   if ($sec  < 10) { $sec  = "0$sec"  }
        !           392:   if ($hour < 10) { $hour = "0$hour" }
        !           393:   if ($mday < 10) { $mday = "0$mday" }
        !           394:   if ($mon  < 10) { $mon  = "0$mon"  }
        !           395: 
        !           396:   my $time = $year . $mon . $mday;
        !           397: 
        !           398:   return $time;
1.3       andrew    399: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>