#!/usr/bin/perl # # Copyright (C) 2000-2004 Astaro AG # For copyright information look at /doc/astaro-license.txt # or http://www.astaro.com/doc/astaro-license.txt # # $Id: ticker.pl,v 1.1 2004/03/30 11:37:36 mgehrlein Exp $ # # Maintainer: Vukasin Toroman # #--------------------------------------------------------------# #=============================================================================# #MAIN_CONFIG #=============================================================================# use Fcntl qw(O_WRONLY); # - - - - # Config File for ticker.pl my $TICKER_CONFIG = "ticker_config.ini"; # - - - - # file for reading information about ha my $ha_file="/etc/wfe/conf/ha"; # - - - - #ips and interface informations my $interfaces_file="/opt/tmpfs/running_itf.conf"; # - - - - # default, overriden by config file settings # - - - - # maximum display string length # - - - - my $maxlen=16; # - - - - # contains ticker module names #### LCD CrystalFontz Specifics ##### $OUTPUT = "/dev/ttyS0"; my $cls = "\x0C" ; # clear display my $cursorhome = "\x01" ; my $contrast = "\x0F"."\x41"; my $reboot = "\x1A"."\x1A"."\x1A"; my $line2 = "\x0D"."\x0A"; ########### my @modules = (); my @errorstrings = ( "Error parsing configfile", "Error executing ticker module", "Unknown Error"); $maxlen = int($ARGV[01]) if($ARGV[0]+0>0); my @DEBUGLEVEL=( "Off", #0 "All", #1 "Parsing config file", #2 "Launching Modules", #3 "Displaying Strings", #4 "Row Display", #5 "Version module", #6 "Uptime module", #7 "Date module", #8 "Diskfree module", #9 "Interfaces Module", #10 "CPU Load Module", #11 "Signal Handler", #12 "AdminMail", #13 "Ha", #14 "UNKNOWN DEBUG LEVEL!"); my %Functions = ( "Ha" => get_ha(), "Interfaces" => get_interfaces(), "CpuLoad" => get_cpuload(), "Date" => get_date(), "Uptime" => get_uptime(), "DiskFree" => get_diskfree(), "Version" => get_version(), "AdminMail" => get_adminmail() ); $| = 1; #=============================================================================# # BEGIN SUBS #=============================================================================# # ------------- sub set_speed # ------------- { my $speed = $MCH->{Global}{Speed}; DEBUG(4,"Speed: $speed"); if (($speed >= 1) && ($speed <= 10)) { # should be reasonable .) $MCH->{'Actual'}{'Speed'} = (1 / ($speed/2)); } else { # take the default and warn LOG_WARN(0,"Ticker speed set to invalid value: speed; Should be 1-10"); } }; # ------------- sub set_writer # ------------- { $MCH->{'Actual'}{'Writer'} = $MCH->{Global}{'Writer'}; }; # ---------- sub sigterm # ---------- { my $output = "System is going down for reboot"; open(F,"> $OUTPUT"); print F $string; close(F); }; # ----------- sub LOG_WARN # ---------- { (my $level, my $msg) = @_; print "WARNING($level): $errorstrings[$level]\n"; print "Error: $msg\n"; }; # -------- sub DEBUG # -------- { if (($MCH->{'Global'}{'Debug'} > 0) && ($_[0] == 99)) { # - - - - # print-my-message in every case, if debug is activated, leaving level aside print "====> IMPORTANT DEBUG: $_[1]\n"; } elsif (($MCH->{'Global'}{'Debug'} == 1) || ($MCH->{'Global'}{'Debug'} == $_[0])) { # if DEBUG == 1, then print every msg; otherwise only print msgs of this level print "DEBUG: $_[1]\n"; } }; # ------------ sub LOG_FATAL # ------------ { (my $errcode, my $msg)=@_; printf "FATAL($errcode): $msg\n"; exit($errcode); exit($errcode); }; # ------- sub max # ------- { my $max = shift (@_); foreach my $foo (@_) { $max = $foo if $max < $foo; } return $max; }; # --------------- sub display_rows # --------------- { $modules = shift; # this sub is 'the intelligence' behind scrolling my @return = (); my $row0=""; my $row1=""; my $count = 0; my $tmod = ''; my $string = ''; my @modules = (); my ($modname, $output, $value) = ('','',''); #### initialize LCD ###### system ( "stty 9600 <$OUTPUT" ); open (F, "> $OUTPUT"); # # Clear and home the LCD display # ------------------------------ # print F "$cls"; print F "$cursorhome"; print F "$cls"; print F "$contrast"; close (F); # as long as we have modules to display, loop foreach $tmod (@$modules) { # try to call module next if $tmod !~ /\w+/; #- - - - - - - - - # set value for each function ($value, $modname, $output) = (undef, undef, undef); $value = $Functions{$tmod}; $modname = "$value->[0]" if defined $value->[0]; $output = "$value->[1]" if defined $value->[1]; if(defined($modname) && defined($output)) { if($modname !~ /\w+/ || $output !~ /\.*/) { LOG_WARN(1,"Error in ticker module \'$tmod\'"); next; } DEBUG(3,"Found function for extension \'$tmod\'\n"); DEBUG(3,"I received: \'$modname\' | \'$output\'\n"); my $scrollin=1; # easiest way: pad every line with 16 whitespaces in front, to enable scroll-in if ($scrollin==1) { DEBUG(4,"Scroll-In enabled"); $modname=' ' x $maxlen.$modname; # maxlen is display length (eg 16 chars) $output=' ' x $maxlen.$output; } my $count=0; my $hioffset=0; my $looffset=0; my $hilen=length($modname); my $lolen=length($output); my $maxscroll=max($hilen,$lolen); my $hiwait=0; my $lowait=0; my $hicharsleft=$hilen; my $locharsleft=$lolen; # - - - - - - - - - - # while longest line hasn't scrolled out while ($count++ < ($maxscroll)) { # shorter line has to wait for longer line if ((($hicharsleft=$hilen-$hioffset-$maxlen) < $maxlen ) && ($count > $maxlen)) { # then we have just maxlen spaces waiting to scroll in $hiwait=1; } if ((($locharsleft=$lolen-$looffset-$maxlen) < $maxlen ) && ($count > $maxlen)) { $lowait=1; } if ($hiwait==1 && $lowait==1) { # both are in 'waiting' state, which means that both have scrolled in fully - # only spaces wait to be scrolled in. # but to make the scroll-out cool, the shorter row has to wait for the longer to catch up if ($hicharsleft == $locharsleft) { # both have the same length left, so we can scroll out DEBUG(4, "Scrolling out\n"); $row0=substr($modname,$hioffset++,$maxlen); $row1=substr($output,$looffset++,$maxlen); } elsif ($hicharsleft > $locharsleft) { DEBUG(4, "Waiting for higher row to catch up!\n"); $row0=substr($modname,$hioffset++,$maxlen); $row1=substr($output,$looffset,$maxlen); } elsif ($locharsleft > $hicharsleft) { DEBUG(4, "Waiting for lower row to catch up!\n"); $row0=substr($modname,$hioffset,$maxlen); $row1=substr($output,$looffset++,$maxlen); } } elsif ($hiwait == 1 && $lowait == 0) { DEBUG(4, "Hi waiting\n"); $row0=substr($modname,$hioffset,$maxlen); $row1=substr($output,$looffset++,$maxlen); } elsif ($hiwait == 0 && $lowait == 1) { DEBUG(4, "LO waiting\n"); $row0=substr($modname,$hioffset++,$maxlen); $row1=substr($output,$looffset,$maxlen); } else { # none is waiting, normal scroll DEBUG(4, "None waiting\n"); $row0=substr($modname,$hioffset++,$maxlen); $row1=substr($output,$looffset++,$maxlen); } DEBUG(4,"Hi-Wait: $hiwait | Lo-Wait: $lowait | Count: $count | HiCharsLeft: $hicharsleft | LoCharsLeft: $locharsleft"); DEBUG(5,"Displaying: \'$row0\' | hioffset: $hioffset"); DEBUG(5,"Displaying: \'$row1\' | looffset: $looffset"); # add type check here $row0 .= ' ' x ($maxlen - length($row0)); $row1 .= ' ' x ($maxlen - length($row1)); $string = "$row0" . $line2 . "$row1"; open(F,"> $OUTPUT"); print F $string; close(F); # print "Row0: $row0\nRow1: $row1\n"; stop(); } } else { LOG_WARN(1,"No (working) ticker module called \'$tmod\'"); } } }; # -------- sub stop # -------- { my $speed = shift; # wait shorter than sleep(1) # get ticker speed by ticker.conf select(undef,undef,undef,$MCH->{'Actual'}{'Speed'}); }; ################################################################### #>>>>>>>>>>>>>>>>>> TICKCER MODULES EXTENSIONS <<<<<<<<<<<<<<<<<<# ################################################################### # ---------- sub get_version # --------- { my @return = (); my $version=""; if (! open(FILE, "< /etc/version")) { LOG_WARN(1,"Can't access /etc/version"); return undef; } else { while () { chomp; $version=$_; $version=~s/^\s*//g; DEBUG(6,"Version is: \'$version\'"); } close(FILE); } @return = ("Astaro Security Linux", "Version: $version"); return \@return; }; # ------- sub get_date # ------- { # print my local time settings # asl has no timezone set .. :| my @return = (); my $ref = \@return; my $now=(`/bin/date +"%a %b %e %T %Y"`); chomp $now; DEBUG(8,"Date is \'$now\'"); @return = ("Today is:",$now); return $ref; }; # ----------- sub get_cpuload # ----------- { # print cpu load averages my @return = (); my $ref = \@return; (my $one,my $two,my $three)=(`cat /proc/loadavg` =~ /(\d+\.\d+)/g); DEBUG(11,"CPU Load is: \'$one $two $three\'"); @return = ("CPU load:","$one $two $three"); return $ref; }; # --------- sub get_uptime # --------- { # print asl uptime my @return = (); my $ref = \@return; my $uptime=""; if (! open(FILE, "< /proc/uptime")) { LOG_WARN(1,"Can't access /proc/uptime"); } else { while () { (my $unixtime, my $trash)=split(/ /); my $days=int($unixtime/86400); my $hours=int(($unixtime-($days*24*3600))/3600); my $mins=int(($unixtime-($days*24*3600)-($hours*3600))/60); $uptime="Up: ".$days." d ".$hours." h ".$mins." m"; } close(FILE); } DEBUG(7,"Uptime is: \'$uptime\'"); @return = ("System uptime:",$uptime); return $ref; }; # ----------- sub get_diskfree # ----------- { # print disk usage my $usage=""; my @return = (); my $ref = \@return; if (!open(FILE,"df -lh | grep dev|")) { LOG_WARN(1,"Diskfree command (df) failed!"); } else { while () { # /dev/hda3 19G 9.4G 8.3G 54% / (my $device, my $size, my $free, my $used, my $percentage, my $mountpoint)=split(/\s+/); $usage eq "" ? ($usage="$mountpoint: $percentage") : ($usage.=" | $mountpoint: $percentage"); } } close(FILE); DEBUG(9,"Disk Usage is: \'$usage\'"); @return = ("Disk Usage:",$usage); return $ref; }; # ------------- sub get_interfaces # ------------- { # shows used interfaces and ips my @tmp; my @return = (); my @interfaces = (); my $ref = \@return; my ($line, $key, $interfaces); my ($address, $inname, $netmask, $type, $hostname, $gateway); my %settings = %{ ini_read($interfaces_file) }; foreach $key(sort keys %settings) { $line = ""; $line .= "Name: $key"; $line .= " Type: $settings{$key}{type}"; $line .= " Ip: $settings{$key}{address}"; $line .= " Interface: $settings{$key}{hardware}" if(exists ($settings{$key}{hardware})); $line .= " Netmask: $settings{$key}{netmask}" if(exists($settings{$key}{netmask})); $line .= " Gateway: $settings{$key}{gateway}"; unshift(@interfaces, $line); } $interfaces = "@interfaces"; DEBUG(10,"Interfaces: \'@interfaces\'"); @return = ("Interfaces:",$interfaces); return $ref; }; # ------ sub get_ha # ------ { # shows high availability status my @return; my $ref = \@return; my $mdw_ok = ""; my $info = ""; my $ret_value; my $key = ""; my %settings = %{ ini_read($ha_file) }; foreach $key(sort (keys %settings)) { next if ($key ne "status"); chomp $key; if($settings{$key}) { $mdw_ok = readpipe "pidof ./mdw_deamon.pl"; chomp $mdw_ok; if($mdw_ok eq "") { $info = "Running in slave mode."; } else { $info = "Running in master mode."; } DEBUG(14,"HA Mode: \'$info\'"); @return = ("HA Mode:", $info); } else { $info = "High Availablitity has $key status!"; DEBUG(14, "HA Mode: \'$info\'"); @return = ("defunc"); } } if(@return == 0) { @return = ("defunc"); } return $ref; }; # ------------- sub get_adminmail # ------------- { # shows administrators email address my @return = (); my $ref = \@return; my $admin_mail =""; if(!open(FILE,"< /etc/adminmail")) { LOG_WARN(1, "Could not open /etc/adminmail"); } else { while() { chomp $_; $admin_mail = "$admin_mail"." "."$_"; } close(FILE); } DEBUG(13,"Adminmail: $admin_mail"); @return= ("Adminmail:", $admin_mail); return $ref; }; # ----------- sub ini_read # ----------- { my %hash = (); my $fname = shift; if (!open(FINI,"< $fname")) { return 0; }; my $section = "UNDEF"; LINE: while() { chop; s/^ +//; s/\#.*$//g; next if (!$_); next if ($_ =~ /^\#/); if ($_ =~ /^\[/) { s/\[(.+)\]//; $section = ini_decode($1); next; } elsif ($_ =~ /\=/) { my ($key,$value) = split / *\= */, $_; $key = ini_decode($key); $value = ini_decode($value); if ($section eq 'global') { $hash{$key} = $value; } else { $hash{$section}{$key} = $value; }; next; } else { my $slice = ini_decode($_); if ($hash{$section} !~ /ARRAY/) { $hash{$section} = [ $slice ]; } else { foreach (@{ $hash{$section} }) { next LINE if ($_ eq $slice); }; push @{ $hash{$section} }, $slice; }; }; }; close(FINI); return \%hash; }; # ------------- sub ini_decode # ------------- { my $str = shift; $str =~ s/\%(..)/chr(hex($1))/eg; return($str); }; #=============================================================================# # This is the main loop for the lcd ticker #=============================================================================# # create fifo while (1) { my @modules = (); local $SIG{TERM}='sigterm'; # - - - - - - - - - # first we read the conf, so you can change the settings while running that thing :) # - - - - - - # Set Main Config Hash $MCH = ini_read($TICKER_CONFIG); map { push(@modules, $_) if($MCH->{Modules}{$_}) } keys %{$MCH->{Modules}}; set_speed(); set_writer(); # - - - - - - # now loop the loading of the modules (so you get topical values) and display them sleep(1); display_rows(\@modules); }