Yet another useful script (see POD comments)

I wrote this one to replace the IVMAN daemon, which somehow became foobarred on my daughter’s Linux box:


#!/usr/bin/perl -w

use strict;

=head1 NAME

ivman.pl – Pure-perl program to replace ivman daemon.

=head1 SYNOPSIS

ivman.pl &

=head1 DESCRIPTION

    I wrote this program to replace ivman, after wasting an entire evening pulling
my hair out trying to figure out why it would no longer respond to any hardware
changes from hal and how I could have possibly bricked one of it’s FOUR XML
config files. 😦

    ivman.pl uses a simple text configuration file for matching "lshal" result
lines and changes, and specifying one or more shell commands to execute.  The file
is either ~/.ivman.cfg, or, if that is not found, /etc/ivman.cfg.  If the source
file is changed from ivman.pl to something else, then the config file name must
match. (~/.<pgmname>.cfg or /etc/<pgmname>.cfg for <pgmname>.pl).  The general
format for each line of the config file is:

<lshal-string-to-match>:<cmd>[;<cmd-2>;…<cmd-n>]

Example:

volume.disc.is_videodvd:/usr/bin/vlc dvd:// &
block.device = ‘/dev/sdb’:/usr/bin/pmount /dev/sdb1;/usr/bin/pmount /dev/sdb2;/usr/bin/pmount /dev/sdb3;/usr/bin/pmount /dev/sdb4

    The 1st line launches vlc to play a dvd, if a dvd disk is inserted into the
dvd player.  Note the ampresand after the command!  The 2nd line attempts to mount
up to 4 partitions of a usb key or hard disk.

    ivman.pl executes "lshal" and processes it’s input every 8 seconds.  This
default can be changed by changing the value of "$pollEverySec" to something else.
It checks each line against all the matching values specified in the configuration
file.  When it finds a match, it invokes each of the corresponding command(s) in
the order they are specified.  Invocation of the commands occurrs only once when
the match is 1st detected in the "lshal" output.  To be invoked again, the matching
line must disappear from "lshal" output and then reappear (hardware removed and
re-inserted).

=cut

my $pollEverySec = ‘8’;     #POLLING FREQUENCY IN SECONDS (DEFAULT EVERY 8 SECONDS)
$ENV{DISPLAY} ||= ‘:0.0’;   #DISPLAY PROBABLY NOT SET WHEN STARTED BY INIT.D!

#our $debug = 0;

our %connected = ();
our %actionHash = ();
my $pgmName = $0;
$pgmName = $1  if ($pgmName =~ m#\/([^\/]+)$#o);
my $cfgName = $pgmName;
$cfgName =~ s/\.pl$//o;
my $cfgFid = $ENV{HOME} . ‘/.’ . $cfgName . ‘.cfg’;
unless (-f $cfgFid) {
    $cfgFid = ‘/etc/’ . $cfgName . ‘.cfg’;
}
die "..$pgmName: no config file (${cfgName}.cfg)!"  unless (-f $cfgFid);
open OUT, ">/tmp/${cfgName}.pid"; print OUT $$; close OUT;

open CFG_IN, $cfgFid;      #PROCESS CONFIGURATION FILE:
my ($pattern, $actions);
while (<CFG_IN>) {
    chomp;
    s/\s*\#.*$//o;
    next  unless (length($_));
    ($pattern, $actions) = split(/\:/, $_, 2);
    $connected{$pattern} = 0;
    $actionHash{$pattern} = [split(/\;/, $actions)];
}
close CFG_IN;

$SIG{INT} = sub {    #CATCH CONTROL-C:
    unlink "/tmp/${cfgName}.pid";
    exit(0);
};

$SIG{ALRM} = sub {    #MAIN LOGIC:
    my %detected = ();
    foreach my $i (keys %connected) {
        $detected{$i} = 0;
    }

    my @lshal = `/usr/bin/lshal`;    #FETCH INPUT FROM "lshal"
    my $line;
    while (@lshal) {                 #PROCESS EACH LINE OF INPUT:
        $line = shift(@lshal);
        chomp $line;
        foreach my $i (keys %connected) {   #CHECK EACH CONFIGURED MATCHING STRING AGAINST THE CURRENT LINE:
            if ($line =~ /$i/) {    #LINE CONTAINS A MATCH, SEE IF THIS HARDWARE ALREADY CONNECTED:
                $detected{$i} = 1;
                unless ($connected{$i}) {   #NO IT’S NOT, EXECUTE DESIRED COMMANDS AND MARK IT AS "CONNECTED":
                    foreach my $j (@{$actionHash{$i}}) {
                        system($j);
                    }
                    $connected{$i} = 1;
                }
            }
        }
    }
    foreach my $i (keys %connected) {   #MARK AS "DISCONNECTED" ANY HARDWARE FOR WHICH THE STRING NO LONGER MATCHED IN "lshal" OUTPUT:
        $connected{$i} = 0  if ($connected{$i} && !$detected{$i});
    }
   
    alarm($pollEverySec);   #SET TIME OF NEXT CHECK:
};

alarm(1);
while (1)
{
    sleep(2000);
}

#SHOULDN’T GET HERE, BUT JUST IN CASE:

unlink "/tmp/${cfgName}.pid";
exit(0);

__END__
 

Advertisements

Feel Free to Comment (Name/Email/Website optional):

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: