hi, monks ...
In the never-ending quest to become a less lame writer of perl programs (hoping to someday be able to proudly have a JAPH sig), I would appreciate any and all comments on this script, which I am posting below.
This program works fine (but is only useful on AIX, which incidently, is NOT being canned in favor of Linux, contrary to postings on various sites, including those who use only non-alphanumeric characters in their names (but I digress))
However, I'm sure that some of ways that I'm doing things are awkward, inefficient, or just plain dumb. I hope that y'all would like to help me be less awkward, inefficient, and dumb.
thanks, and try to be gentle (well, not *too* gentle, but I don't think I have to worry about that. :-)
#!/usr/local/bin/perl -w
#=====================================================================
# cinnamon -- a perl script that translates the sense data from SIM
# and MIM messages posted by IBM 3590 tape drives into
# human-readable format, and sends the messages via email
#---------------------------------------------------------------------
# $Id: cinnamon,v 1.1 2001/08/21 04:48:51 ssklar Exp $
#=====================================================================
use strict;
$|++;
unless ($^O =~ /aix/) {
die "Cinnamon is only useful on AIX systems. Sorry.\n"
};
#---------------------------------------------------------------------
+-
# the email address(es) that the formatted error message is to be sent
# to. Don't forget to backslash any "@" signs ...
#---------------------------------------------------------------------
+-
my $recipient = "root";
unless (defined($recipient)) { $recipient = "root" }
#---------------------------------------------------------------------
+-
# the sequence number of the error log entry that we were invoked for
# will be passed as the single argument ...
#---------------------------------------------------------------------
+-
my $sequence_number = shift ||
die "cinnamon: sequence number needed as argument\n";
#---------------------------------------------------------------------
+-
# read in the full unformatted error log entry with the specified
# sequence number ...
#---------------------------------------------------------------------
+-
open (ERROR, "/usr/bin/errpt -g -l $sequence_number |");
#------------------------------------------------------------------
# pull out the detail data from the error log entry ...
#------------------------------------------------------------------
my %message;
while (<ERROR>) {
if (/^el_nodeid/) {
(undef, $message{host}) = split (/\s+/, $_); next
};
if (/^el_resource/) {
(undef, $message{drive}) = split (/\s+/, $_); next
};
if (/^el_detail_data/) {
(undef, $message{detail}) = split (/\s+/, $_); last
};
};
close (ERROR);
#------------------------------------------------------------------
# get the "Machine Type" and convert it from hex to ascii ...
#------------------------------------------------------------------
substr($message{detail}, 128, 10) =~ /(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)/;
$message{machine_type} = pack ("CCCCC", hex($1), hex($2), hex($3), hex
+($4), hex($5));
#------------------------------------------------------------------
# get the "Model" and convert it from hex to ascii ...
#------------------------------------------------------------------
substr($message{detail}, 138, 6) =~ /(\w\w)(\w\w)(\w\w)/;
$message{model} = pack ("CCC", hex($1), hex($2), hex($3));
#------------------------------------------------------------------
# get the "Model and Microcode Level" and convert it from hex
# to ascii ...
#------------------------------------------------------------------
+
substr($message{detail}, 32, 8) =~ /(\w\w)(\w\w)(\w\w)(\w\w)/;
$message{mml} = pack ("CCCC", hex($1), hex($2), hex($3), hex($4));
#------------------------------------------------------------------
# get the "Message Code" and look up it's meaning ...
#------------------------------------------------------------------
my %message_code = (
3030 => "No Message",
3430 => "Operator Intervention Required",
3431 => "Device Degraded",
3432 => "Device Hardware Failure",
3433 => "Service Circuits Failed, Operations not Affected",
3535 => "Clean Device",
3537 => "Device has been cleaned",
3630 => "Bad Media, Read-Only Permitted",
3631 => "Rewrite Data if Possible",
3632 => "Read Data if Possible",
3634 => "Bad Media, Cannot Read or Write",
3732 => "Replace Cleaner Cartridge"
);
$message{code} = $message_code{substr($message{detail}, 40, 4)} || "UN
+KNOWN";
#------------------------------------------------------------------
# determine if we're dealing with a SIM or a MIM ...
#------------------------------------------------------------------
if (substr($message{detail}, 16, 2) eq "01") {
#--------------------------------------------------------------
# it's a SIM ...
#--------------------------------------------------------------
$message{type} = "SIM";
#--------------------------------------------------------------
# convert the FID Severity Code into something meaningful ...
#--------------------------------------------------------------
my %fid_severity_code = (
33 => "1 -- Acute",
32 => "2 -- Serious",
31 => "3 -- Moderate",
30 => "4 -- Service"
);
$message{severity} = $fid_severity_code{substr($message{detail}, 5
+2, 2)} || "UNKNOWN";
#--------------------------------------------------------------
# get the FID (FRU Identification Number), and convert it from
# hex to ascii ...
#--------------------------------------------------------------
substr($message{detail}, 64, 4) =~ /(\w\w)(\w\w)(\w\w)/;
$message{fid} = pack ("CC", hex($1), hex($2));
#--------------------------------------------------------------
# get the "First FSC" (Fault Symptom Code), and convert it from
# hex to ascii ...
#--------------------------------------------------------------
substr($message{detail}, 68, 8) =~ /(\w\w)(\w\w)(\w\w)(\w\w)/;
$message{first_fsc} = pack ("CCCC", hex($1), hex($2), hex($3), hex
+($4));
#--------------------------------------------------------------
# get the "Last FSC" (Fault Symptom Code), and convert it from
# hex to ascii ...
#--------------------------------------------------------------
substr($message{detail}, 76, 8) =~ /(\w\w)(\w\w)(\w\w)(\w\w)/;
$message{last_fsc} = pack ("CCCC", hex($1), hex($2), hex($3), hex(
+$4));
} else {
#--------------------------------------------------------------
# it's a MIM ...
#--------------------------------------------------------------
$message{type} = "MIM";
#--------------------------------------------------------------
# convert the MIM Severity Code into something meaningful ...
#--------------------------------------------------------------
my %mim_severity_code = (
31 => "3 -- Moderate: high temporary read or write e
+rrors have occurred",
32 => "2 -- Serious: permanent read or write errors
+ have occurred",
33 => "1 -- Acute: tape directory errors have occurr
+ed"
);
$message{severity} = $mim_severity_code{substr($message{detail}, 5
+2, 2)} || "UNKNOWN";
#--------------------------------------------------------------
# get the VOLSER (Volume Serial Number), and convert it from
# hex to ascii ...
#--------------------------------------------------------------
substr($message{detail}, 68, 12) =~ /(\w\w)(\w\w)(\w\w)(\w\w)(\w\w
+)(\w\w)/;
$message{volser} = pack ("CCCCCC", hex($1), hex($2), hex($3), hex(
+$4), hex($5), hex($6));
};
#------------------------------------------------------------------
# format the data and store it in the array @mail ...
#------------------------------------------------------------------
my @mail;
push (@mail, sprintf("Subject: %s posted by %s: %s\n", $message{type}
+, $message{drive}, $message{code}));
push (@mail, sprintf("%-16s: %-20s\n", "Sequence Number", $sequence_nu
+mber));
push (@mail, sprintf("%-16s: %-20s\n", "Host", $message{hos
+t}));
push (@mail, sprintf("%-16s: %-20s\n", "Drive", $message{dri
+ve}));
push (@mail, sprintf("%-16s: %-20s\n", "Model", $message{mod
+el}));
push (@mail, sprintf("%-16s: %-20s\n", "Microcode", $message{mml
+}));
push (@mail, sprintf("%-16s: %-20s\n", "Message Type", $message{typ
+e}));
push (@mail, sprintf("%-16s: %-20s\n", "Message Code", $message{cod
+e}));
push (@mail, sprintf("%-16s: %-20s\n", "Severity", $message{sev
+erity}));
if ($message{type} eq "SIM") {
push (@mail, sprintf("%-16s: %-20s\n", "First FSC", $message{fir
+st_fsc}));
push (@mail, sprintf("%-16s: %-20s\n", "Last FSC", $message{las
+t_fsc}));
} else {
push (@mail, sprintf("%-16s: %-20s\n", "VOLSER", $message{vo
+lser}));
};
push (@mail, "\n\nRaw Sense Data:\n$message{detail}\n" . "-" x 72 . "\
+n\n");
#------------------------------------------------------------------
# open a pipe to sendmail and sent the message ...
#------------------------------------------------------------------
open (SENDMAIL, "|/usr/sbin/sendmail $recipient") or
die "cinnamon: couldn't open sendmail: $!";
print SENDMAIL @mail;
close (SENDMAIL);
exit 0;
#---------------------------------------------------------------------
+-
# documentation
#---------------------------------------------------------------------
+-
=pod
=head1 NAME
cinnamon -- translates the sense data from SIM and MIM messages
posted by IBM 3590 tape drives to the AIX error log into human-
readable format, and sends the messages via email.
=head1 DESCRIPTION
B<cinnamon> (so named because I thought it sounded like "sim-mim-
mon", which was my original name for the program) parses and mails
AIX error log entries posted with the identifier B<D1A1AE6F>, which is
+
the ERROR ID for B<SIM_MIM_RECORD_3590>.
SIM and MIM records are part of the "Statistical Analysis and Reportin
+g
System" (SARS), and are messages created by IBM 3590 tape drives that
report on the condition of the drive (a SIM) or of the medium (a MIM)
+.
These records are presented by the operating system in different ways.
In AIX, they are recorded in the error log, but in a difficult-to-re
+ad format.
This script breaks down the sense data where the information is stored
+,
parses it into a human-understandable format, and mails it to root.
=head1 SETUP/USAGE
If the user wants emails sent by this program to be sent to any other
address than B<root>, the variable B<$recipient> should be changed
(about line number 26) to that address (or those addresses, comma-
separated but all contained within double-quotes, with any "@" signs
back-slashed.
Additionally, this program is meant to be used as B<errnotify method>,
added to the ODM, so that B<cinnamon> will be invoked each time an
error log entry that matches the descriptor values of a 3590 SIM or MI
+M
message.
To create the B<errnotify method>, save the following text to the file
+ B</tmp/cinnamon.add>:
errnotify:
en_name = "cinnamon"
en_persistenceflg = 1
en_label = "SIM_MIM_RECORD_3590"
en_class = "H"
en_type = "INFO"
en_method = "/usr/local/bin/perl /usr/local/sbin/cinnamon $1"
(Note: use the proper paths to your perl executible and to this progra
+m
in the above "en_method" line.)
After saving the above text to a file, run the command:
odmadd /tmp/cinnamon.add
The error notification object will be added to the ODM. To verify tha
+t
the object was added to the ODM properly, run the command:
odmget -q"en_name='cinnamon'" errnotify
To remove the object from the ODM (why would you want to do that?),
run the command:
odmdelete -q"en_name='cinnamon'" -o errnotify
=head1 AUTHOR
Sandor W. Sklar
Unix Systems Administrator
Stanford University ITSS
mailto:ssklar@stanford.edu
http://whippet.stanford.edu/~ssklar/
If this script is useful to you, or even if it is useless to you, or
+you have
some changes/improvements/questions/large sums of cash and nothing
to do with it, please send me an email.
=head1 FOR MORE INFORMATION
Most of the things that this script does were taken from the IBM
publication "Statistical Analysis and Reporting System User Guide", wh
+ich
can be downloaded from <http://www.storage.ibm.com/hardsoft/tape/pubs
+/pubs3590.html>.
Information about creating custom error notification objects can be
found in Chapter 4 of the IBM manual "General Programming Concepts:
Writing and Debugging Programs", available online at
< http://www.rs6000.ibm.com/doc_link/en_US/a_doc_lib/aixprggd/genprogc
+/error_notice.htm>
=head1 COPYRIGHT
This program is free software; you may redistribute it and/or modify i
+t
under the same terms as Perl itself.
=cut
#---------------------------------------------------------------------
+-
# version history
#---------------------------------------------------------------------
+-
# $Log: cinnamon,v $
# Revision 1.1 2001/08/21 04:48:51 ssklar
# Initial revision
#