[BACK]Return to check_hw_sensors CVS log [TXT][DIR] Up to [local] / nagios / check_hw_sensors

Annotation of nagios/check_hw_sensors/check_hw_sensors, Revision 1.25

1.14      andrew      1: #!/usr/bin/perl -T
1.25    ! andrew      2: # $RedRiver: check_hw_sensors,v 1.24 2007/02/14 21:59:10 andrew Exp $
1.2       andrew      3: ########################################################################
                      4: # check_hw_sensors *** A nagios check for OpenBSD hw.sensors
                      5: #
                      6: # 2006.05.01 #*#*# andrew fresh <andrew@mad-techies.org>
                      7: ########################################################################
1.4       andrew      8: # TODO:
1.12      andrew      9: #   Really need real documentation.
1.24      andrew     10: #   allow checking of hw.sensors on a remote host with ssh somehow
1.4       andrew     11: ########################################################################
1.2       andrew     12: use strict;
                     13: use warnings;
                     14:
1.14      andrew     15: %ENV = ();
                     16:
1.24      andrew     17: use constant NAGIOS_OUTPUT => 1;
1.4       andrew     18:
1.2       andrew     19: use POSIX;
1.20      andrew     20: use Config;
1.4       andrew     21: use lib "/usr/local/libexec/nagios";
1.2       andrew     22: use utils qw($TIMEOUT %ERRORS &print_revision &support);
                     23:
                     24: use Getopt::Long;
                     25: Getopt::Long::Configure('bundling');
                     26:
                     27: my $PROGNAME = "check_hw_sensors";
                     28:
1.4       andrew     29: my $SYSCTL = '/sbin/sysctl';
                     30: my $GETCAP = '/usr/bin/getcap';
1.2       andrew     31: my $BASE   = 'hw.sensors';
1.4       andrew     32: my $DEFAULT_CONFIG = '/etc/sensorsd.conf';
1.20      andrew     33: my $OSVer = $Config{'osvers'} || 0;
1.2       andrew     34:
                     35: my $state = 'UNKNOWN'; # tells whether the it is warning, critical, or OK
                     36: my %states; # This stores the count of states;
                     37: my $filename;
1.15      andrew     38: my $ignore_status;
1.2       andrew     39: my $sensor;
                     40: my $warning;
                     41: my $critical;
1.10      andrew     42: my $opt_h;
                     43: my $opt_V;
1.2       andrew     44:
1.4       andrew     45: my $CHECK_SENSOR = $BASE;
                     46: my %CHECKS;
                     47: my %SENSORS;
1.2       andrew     48:
                     49: #Option checking
                     50: my $status = GetOptions(
1.15      andrew     51:        "version|V"       => \$opt_V,
                     52:        "filename|f:s"    => \$filename,
                     53:        "ignore-status|i" => \$ignore_status,
                     54:        "sensor|s=s"      => \$sensor,
                     55:        "warning|w=s"     => \$warning,
                     56:        "critical|c=s"    => \$critical,
1.2       andrew     57: );
1.18      andrew     58:
1.2       andrew     59: # set the default this way so it only happens if someone typed -f or --filename
1.4       andrew     60: $filename = $DEFAULT_CONFIG if (defined $filename && $filename eq '');
1.2       andrew     61:
1.18      andrew     62: # Stuff is output in this file by print_sensor()
                     63: # http://www.openbsd.org/cgi-bin/cvsweb/src/sbin/sysctl/sysctl.c
                     64: my @Type_Map = (
                     65:        {
                     66:                type  => 'temp',
                     67:                regex => qr/\sdegC$/,
                     68:        },
                     69:        {
                     70:                type  => 'fanrpm',
                     71:                regex => qr/\sRPM$/,
                     72:        },
                     73:        {
                     74:                type  => 'volts_dc',
                     75:                regex => qr/\sV\sDC$/,
                     76:        },
                     77:        {
                     78:                type  => 'amps',
                     79:                regex => qr/\sA$/,
                     80:        },
                     81:        {
                     82:                type  => 'watthour',
                     83:                regex => qr/\sWh$/,
                     84:        },
                     85:        {
                     86:                type  => 'amphour',
                     87:                regex => qr/\sAh$/,
                     88:        },
                     89:        {
                     90:                type  => 'indicator',
                     91:                regex => qr/^(On|Off)$/,
                     92:        },
                     93:        {
                     94:                type  => 'integer',
                     95:                regex => qr/\sraw$/,
                     96:        },
                     97:        {
1.19      andrew     98:                type  => 'percent',
                     99:                regex => qr/\s\%$/,
                    100:        },
                    101:        {
1.18      andrew    102:                type  => 'lux',
                    103:                regex => qr/\slx$/,
                    104:        },
                    105:        {
                    106:                type  => 'drive',
                    107:                regex => qr/^drive\s/,
                    108:        },
                    109:        {
                    110:                type  => 'timedelta',
                    111:                regex => qr/\ssecs$/,
                    112:        },
                    113: );
                    114:
1.2       andrew    115: if ($status == 0) {
                    116:        print_help() ;
                    117:        exit $ERRORS{'OK'};
                    118: }
                    119:
                    120: if ($opt_V) {
1.25    ! andrew    121:        print_revision($PROGNAME,'$Revision: 1.24 $ ');
1.2       andrew    122:        exit $ERRORS{'OK'};
                    123: }
                    124:
1.15      andrew    125: unless (
                    126:        (
1.10      andrew    127:                defined $filename ||
1.15      andrew    128:                (not defined $ignore_status) ||
1.10      andrew    129:                (defined $sensor && ($warning || $critical))
                    130:          ) &&
                    131:          ( (!defined $filename) || (!defined $sensor) )
1.2       andrew    132: ) {
                    133:        print_help();
                    134:        exit $ERRORS{'OK'};
                    135: }
                    136:
                    137:
                    138: if (defined $sensor) {
                    139:        if ($sensor !~ /^$BASE/) {
                    140:                $sensor = $BASE . '.' . $sensor;
                    141:        }
                    142:        $CHECK_SENSOR = $sensor;
                    143:
1.15      andrew    144:        $CHECKS{$sensor}{'warn'} = $warning  if defined $warning;
                    145:        $CHECKS{$sensor}{'crit'} = $critical if defined $critical;
                    146:
1.2       andrew    147: } elsif (defined $filename) {
                    148:        %CHECKS = parse_file($filename);
                    149: }
                    150:
                    151: open my $sysctl, "-|", $SYSCTL, $CHECK_SENSOR
                    152:     or die "Couldn't open sysctl: $!";
                    153: while (<$sysctl>) {
                    154: #while (<>) {
                    155:        chomp;
                    156:        my ($id, $output) = split /=/;
1.22      andrew    157:        my @s = split /\./, $id;
1.2       andrew    158:        my @o = split /,\s*/, $output;
                    159:
1.18      andrew    160:        my ($type, $source, $descr, $data, $status);
                    161:
                    162:        $source = $o[0];
                    163:        $descr  = $o[1];
                    164:
1.25    ! andrew    165:        if ($OSVer >= 4.1) {
1.22      andrew    166:                $data   = $o[0];
1.23      andrew    167:                if ($data =~ s/\s+\((.*)\).*$//) {
                    168:                        $descr = $1;
                    169:                }
                    170:                $status = $o[1];
1.25    ! andrew    171:                ($source, $type) = $id =~ /([^\.]+)\.([^\.]+?)\d+$/;
1.22      andrew    172:        } elsif ($OSVer >= 4.0) {
1.20      andrew    173:                $data   = $o[2];
                    174:                $status = $o[3];
1.18      andrew    175:                foreach my $t (@Type_Map) {
                    176:                        if ($data =~ /$t->{'regex'}/) {
                    177:                                $type = $t->{'type'};
                    178:                                last;
                    179:                        }
                    180:                }
1.20      andrew    181:        }  else {
                    182:                $data   = $o[-1];
                    183:                $status = $o[2] if @o == 5;
                    184:                $type   = $o[-2];
1.18      andrew    185:        }
                    186:
                    187:        $type ||= 'unknown';
1.2       andrew    188:
                    189:        $SENSORS{$id} = {
                    190:                id          => $id,
                    191:                output      => $output,
                    192:                source      => $source,
                    193:                description => $descr,
                    194:                status      => $status,
                    195:                type        => $type,
                    196:                data        => $data,
                    197:        };
                    198:
                    199: }
                    200: close $sysctl;
                    201:
                    202: sub as_if_numeric {
                    203:        my $_a = $a;
                    204:        my $_b = $b;
                    205:        $_a =~ s/\D//g;
                    206:        $_b =~ s/\D//g;
                    207:        $_a <=> $_b;
                    208: }
                    209:
1.15      andrew    210: foreach my $s (sort as_if_numeric keys %SENSORS) {
                    211:        my ($r, $data);
                    212:        if (exists $CHECKS{$s}) {
                    213:                $r    = check_sensor($SENSORS{$s}, $CHECKS{$s});
                    214:                $data = $s . '=' . $SENSORS{$s}{'output'};
                    215:        } elsif (not $ignore_status) {
                    216:                $r = check_sensor($SENSORS{$s});
                    217:                $data = $s . '=' . $SENSORS{$s}{'output'};
1.2       andrew    218:        } else {
1.15      andrew    219:                # ignore this sensor
1.2       andrew    220:        }
1.15      andrew    221:        next unless defined $r;
                    222:        push @{ $states{ $r } }, $data;
1.2       andrew    223: }
                    224:
                    225: $state = 'OK';
1.5       andrew    226: my $have_results = 0;
                    227: foreach my $error (sort { $ERRORS{$a} <=> $ERRORS{$b} } keys %ERRORS) {
                    228:        if (exists $states{$error}) {
                    229:                $have_results++;
                    230:                $state = $error;
                    231:        }
                    232: }
1.4       andrew    233: foreach my $error (sort { $ERRORS{$b} <=> $ERRORS{$a} } keys %ERRORS) {
                    234:        if (exists $states{$error}) {
                    235:                if (NAGIOS_OUTPUT) {
1.8       andrew    236:                        print "$error (" . scalar(@{ $states{ $error } }) . ")";
1.5       andrew    237:                        unless ($error eq 'OK') {
1.9       andrew    238:                                print '<br>';
1.15      andrew    239:                                print map {" - $_<br>"} @{ $states{ $error } };
1.4       andrew    240:                        }
                    241:                } else {
                    242:                        print "$error (" . scalar(@{ $states{ $error } }) . "):\n";
                    243:                        foreach (@{ $states{ $error } }) {
                    244:                                print "   $_\n";
                    245:                        }
                    246:                }
                    247:        }
                    248: }
1.5       andrew    249: if ($have_results == 0) {
                    250:        print "No results found\n";
                    251: }
1.2       andrew    252: exit $ERRORS{$state};
                    253:
                    254:
                    255: sub parse_file {
                    256:        my $filename = shift;
                    257:        my %contents;
1.15      andrew    258:
                    259:        die "file '$filename' does not exist." unless -e $filename;
1.2       andrew    260:
                    261:        open my $fh, '-|', $GETCAP, '-a', '-f', $filename
                    262:                or die "Couldn't open FILE '$GETCAP -a -f $filename': $!";
1.15      andrew    263:        LINE: while (<$fh>) {
1.2       andrew    264:                chomp;
                    265:                my ($key, @c) = split /\:/;
                    266:                foreach (@c) {
                    267:                        my ($k, $v) = split /\=/;
1.15      andrew    268:                        if (lc($k) eq 'ignore') {
                    269:                                $contents{$key}{'IGNORE'} = 1;
                    270:                        } elsif (lc($k) eq 'status') {
                    271:                                $contents{$key}{'STATUS'} = 1;
                    272:                        } else {
                    273:                                $contents{$key}{$k} = $v;
                    274:                        }
1.2       andrew    275:                }
                    276:        }
                    277:        close $fh;
                    278:
                    279:        return %contents;
                    280: }
                    281:
                    282: sub parse_check {
                    283:        my $type  = shift;
                    284:        my $check = shift;
                    285:
1.15      andrew    286:        return undef unless $check;
                    287:        return undef    if $check->{'STATUS'};
                    288:        return 'IGNORE' if $check->{'IGNORE'};
                    289:
1.10      andrew    290:        foreach my $code ('crit', 'warn') {
                    291:                if (defined $check->{$code} && $check->{$code} =~ /:/) {
                    292:                        if (my ($low, $high) = split /:/, $check->{$code}) {
                    293:                                $check->{$code . '.low'}  = $low;
                    294:                                $check->{$code . '.high'} = $high;
                    295:                        }
                    296:                        delete $check->{$code};
1.2       andrew    297:                }
1.10      andrew    298:
                    299:                foreach my $severity ('low', 'high') {
                    300:                        if (defined $check->{$severity}) {
                    301:                                $check->{ $code . '.' . $severity } = $check->{$severity}
                    302:                                        unless defined $check->{ $code . '.' . $severity };
                    303:                        }
1.2       andrew    304:                }
1.10      andrew    305:                no warnings 'uninitialized';
                    306:                $check->{$code} = [ split /,\s*/, $check->{$code} ];
1.2       andrew    307:        }
                    308:
                    309:        return $check;
                    310: }
                    311:
                    312: sub check_sensor {
1.15      andrew    313:        my $sensor = shift;
1.2       andrew    314:        my $check  = shift;
                    315:        my $result = 'UNKNOWN';
                    316:        my %errors = (
                    317:                'warn' => 'WARNING',
                    318:                'crit' => 'CRITICAL',
                    319:        );
                    320:
                    321:        return $result unless ref $sensor eq 'HASH';
1.15      andrew    322:        $check = parse_check($sensor->{'type'}, $check) if $check;
                    323:
1.20      andrew    324:        # It looks like doing this should be safe, from
                    325:        # src/sbin/sysctl/sysctl.c
                    326:        return $sensor->{'status'} unless $check;
1.2       andrew    327:
1.15      andrew    328:        return undef if $check eq 'IGNORE';
1.2       andrew    329:
                    330:        $result = 'OK';
                    331:        foreach my $code ('warn', 'crit') {
                    332:                if (
1.23      andrew    333:                        $sensor->{'type'} eq 'fan'      ||
1.20      andrew    334:                        $sensor->{'type'} eq 'fanrpm'   ||
1.22      andrew    335:                        $sensor->{'type'} eq 'volt'     ||
1.2       andrew    336:                        $sensor->{'type'} eq 'volts_dc' ||
1.20      andrew    337:                        $sensor->{'type'} eq 'amps'     ||
                    338:                        $sensor->{'type'} eq 'watthour' ||
                    339:                        $sensor->{'type'} eq 'amphour'  ||
                    340:                        $sensor->{'type'} eq 'integer'  ||
                    341:                        $sensor->{'type'} eq 'raw'      ||
                    342:                        $sensor->{'type'} eq 'percent'  ||
                    343:                        $sensor->{'type'} eq 'lux'      ||
                    344:                        $sensor->{'type'} eq 'timedelta'
1.2       andrew    345:                ) {
                    346:                        my $data = $sensor->{'data'};
                    347:                        $data =~ s/[^\d\.]//g;
                    348:                        unless (length $data) {
                    349:                                warn "INVALID DATA ($sensor->{'data'}) for '$sensor->{'id'}'";
                    350:                                next;
                    351:                        }
                    352:
                    353:                        if (
                    354:                                defined $check->{$code . ".low"} ||
                    355:                                defined $check->{$code . ".high"}
                    356:                        ) {
                    357:                                if (defined $check->{$code . ".low"}) {
                    358:                                        my $c =  $check->{$code . ".low"};
                    359:                                        $c =~ s/[^\d\.]//g;
                    360:
                    361:                                        unless (length $c) {
                    362:                                                warn "INVALID CHECK (" . $check->{$code . ".low"} .
                    363:                                                      ") for '$sensor->{'id'}:$code.low'";
                    364:                                                next;
                    365:                                        }
                    366:
                    367:                                        $result = $errors{$code}
                    368:                                                if ($c >= $data);
                    369:                                }
                    370:                                if (defined $check->{$code . ".high"}) {
                    371:                                        my $c =  $check->{$code . ".high"};
                    372:                                        $c =~ s/[^\d\.]//g;
                    373:                                        unless (length $c) {
                    374:                                                warn "INVALID CHECK (" . $check->{$code . ".high"} .
                    375:                                                      ") for '$sensor->{'id'}:$code.high'";
                    376:                                                next;
                    377:                                        }
                    378:
                    379:                                        $result = $errors{$code}
                    380:                                                if ($c <= $data);
                    381:                                }
1.9       andrew    382:                        } elsif (@{ $check->{$code} }) {
1.2       andrew    383:                                my $matched = 0;
                    384:                                foreach my $c (@{ $check->{$code} }) {
                    385:                                        $c =~ s/[^\d\.]//g;
                    386:                                        unless (length $c) {
1.7       andrew    387:                                                warn "INVALID CHECK (" . $c .
1.2       andrew    388:                                                      ") for '$sensor->{'id'}:$code'";
                    389:                                                next;
                    390:                                        }
                    391:
1.15      andrew    392:                                        if ($c eq $data) {
1.2       andrew    393:                                                $matched = 1;
                    394:                                                last;
                    395:                                        }
                    396:                                }
                    397:                                $result = $errors{$code} unless $matched;
                    398:                        }
                    399:
                    400:                } elsif ($sensor->{'type'} eq 'temp') {
                    401:                        my ($degC, $degF) = split /\//, $sensor->{'data'};
                    402:                        $degC =~ s/[^\d\.]//g;
1.18      andrew    403:                        $degF ||= $degC * 9 / 5 + 32;
1.2       andrew    404:                        $degF =~ s/[^\d\.]//g;
                    405:                        if (
                    406:                                defined $check->{$code . ".low"} ||
                    407:                                defined $check->{$code . ".high"}
                    408:                        ) {
                    409:                                if (defined $check->{$code . ".low"}) {
                    410:                                        my $c =  $check->{$code . ".low"};
                    411:                                        my $data = $degC;
                    412:
                    413:                                        $data = $degF if ($c =~ /F/i);
                    414:                                        unless (length $data) {
                    415:                                                warn "INVALID DATA (" . $sensor->{'data'} .
                    416:                                                          ") for '$sensor->{'id'}'";
                    417:                                                next;
                    418:                                        }
                    419:
                    420:                                        $c =~ s/[^\d\.]//g;
                    421:                                        unless (length $c) {
                    422:                                                warn "INVALID CHECK (" . $check->{$code . ".low"} .
                    423:                                                         ") for '$sensor->{'id'}':$code.low";
                    424:                                                next;
                    425:                                        }
                    426:
                    427:                                        $result = $errors{$code}
                    428:                                                if ($c >= $data);
                    429:                                }
                    430:                                if (defined $check->{$code . ".high"}) {
                    431:                                        my $c =  $check->{$code . ".high"};
                    432:
                    433:                                        my $data = $degC;
                    434:                                        $data = $degF if ($c =~ /F/i);
                    435:                                        unless (length $data) {
                    436:                                                warn "INVALID DATA (" . $sensor->{'data'} .
                    437:                                                          ") for '$sensor->{'id'}'";
                    438:                                                next;
                    439:                                        }
                    440:
                    441:                                        $c =~ s/[^\d\.]//g;
                    442:                                        unless (length $c) {
                    443:                                                warn "INVALID CHECK (" . $check->{$code . ".high"} .
                    444:                                                         ") for '$sensor->{'id'}:$code.high'";
                    445:                                                next;
                    446:                                        }
                    447:
                    448:                                        $result = $errors{$code}
                    449:                                                if ($c <= $data);
                    450:                                }
1.9       andrew    451:                        } elsif (@{ $check->{$code} }) {
1.2       andrew    452:
                    453:                                my $matched = 0;
                    454:                                foreach my $c (@{ $check->{$code} }) {
                    455:                                        my $data = $degC;
                    456:
                    457:                                        $data = $degF if ($c =~ /F/i);
                    458:                                        unless (length $data) {
                    459:                                                warn "INVALID DATA (" . $sensor->{'data'} .
                    460:                                                          ") for '$sensor->{'id'}'";
                    461:                                                next;
                    462:                                        }
                    463:
                    464:                                        $c =~ s/[^\d\.]//g;
                    465:                                        unless (length $c) {
1.7       andrew    466:                                                warn "INVALID CHECK (" . $c .
1.2       andrew    467:                                                         ") for '$sensor->{'id'}':$code";
                    468:                                                next;
                    469:                                        }
                    470:
1.15      andrew    471:                                        if ($c eq $data) {
1.2       andrew    472:                                                $matched = 1;
                    473:                                                last;
                    474:                                        }
                    475:                                }
                    476:                                $result = $errors{$code} unless $matched;
                    477:                        }
                    478:
                    479:                } elsif (
                    480:                        $sensor->{'type'} eq 'drive' ||
                    481:                        $sensor->{'type'} eq 'indicator'
                    482:                ) {
1.21      andrew    483:                        $sensor->{'data'} =~ s/^drive\s+//;
1.9       andrew    484:                        if (@{ $check->{$code} }) {
1.2       andrew    485:                                my $matched = 0;
                    486:                                foreach (@{ $check->{$code} }) {
                    487:                                        if ($_ eq $sensor->{'data'}) {
                    488:                                                $matched = 1;
                    489:                                                last;
                    490:                                        }
                    491:                                }
                    492:                                $result = $errors{$code} unless $matched;
                    493:                        }
                    494:
                    495:                } else {
1.20      andrew    496:                        print STDERR 'Unknown Sensor Type: ',
                    497:                            $sensor->{'id'},
                    498:                            '=',
                    499:                            $sensor->{'type'},
                    500:                            "\n";
1.2       andrew    501:                        $result = 'UNKNOWN';
                    502:                }
                    503:
                    504:        }
                    505:
                    506:        return $result;
                    507: }
                    508:
                    509: sub print_help {
                    510:        print <<EOL;
                    511: $PROGNAME plugin for Nagios monitors sysctl hw.sensors on OpenBSD
1.15      andrew    512:     $PROGNAME [-i] (-f [<FILENAME>]|(-s <hw.sensors id> [-w limit] [-c limit]))
1.2       andrew    513:
                    514: Usage:
1.15      andrew    515:     -i, --ignore-status
1.17      andrew    516:         Don't check the status of sensors that report it.
1.12      andrew    517:     -f, --filename=FILE
                    518:         FILE to load checks from (defaults to /etc/sensorsd.conf)
                    519:     -s, --sensor=ID
                    520:         ID of a single sensor.  "-s 0" means hw.sensors.0.
                    521:     -w, --warning=RANGE or single ENTRY
                    522:         Exit with WARNING status if outside of RANGE or if != ENTRY
1.13      andrew    523:     -c, --critical=RANGE or single ENTRY
1.12      andrew    524:         Exit with CRITICAL status if outside of RANGE or if != ENTRY
                    525:
1.13      andrew    526: FILE is in the same format as sensorsd.conf(5) plus some additional
                    527: entries.  These additional entries in the file are ignored by
                    528: sensorsd(8).
1.12      andrew    529:
                    530: $PROGNAME understands the following entries:
                    531:
1.15      andrew    532:     low, high, crit, warn, crit.low, crit.high, warn.low, warn.high,
                    533:     ignore, status
1.12      andrew    534:
                    535: An ENTRY depends on the type.  The descriptions in sensorsd.conf(5)
                    536: can be used when appropriate, or you can use the following:
                    537:
1.20      andrew    538:     fanrpm, volts_dc, amps, watthour, amphour, integer (raw), percent,
                    539:     lux or timedelta - Anything that includes digits.  Both the value of
                    540:     the check and the value of the sensor response that are not either a
                    541:     digit or period are stripped and then the two resultant values are
                    542:     compared.
1.12      andrew    543:
                    544:     temp - Can be as above, but if the entry has an F in it,
                    545:     it compares farenheit, otherwise it uses celcius.
                    546:
                    547:     indicator or drive - does a case sensitive match of each
                    548:     entry in the comma separated list and if it does not match
1.20      andrew    549:     any of the entries, it sets the status.
1.12      andrew    550:
                    551: The entries 'crit' or 'warn' (or the -c or -w on the command line)
                    552: may be a RANGE or a comma separated list of acceptable values.
                    553: The comma separated list of values contains a list of things that
                    554: will NOT cause the status.  This is possibly counterintuitive, but
                    555: you are more likely to know good values than bad values.
                    556:
                    557: A RANGE is a low ENTRY and a high ENTRY separated by a colon (:).
                    558: It can also be low: or :high with the other side left blank to only
                    559: make the single check..
1.2       andrew    560:
1.15      andrew    561: An entry marked "ignore" will cause that sensor to be skipped.
                    562: Generally used with state checking of all sensors to ignore sensors you
                    563: don't care about or that report incorrectly.
                    564:
                    565: If you are using --ignore-status, you can still check the status of
                    566: individual sensors with a status entry.
                    567:
1.2       andrew    568: EOL
1.15      andrew    569:
1.25    ! andrew    570:         print_revision($PROGNAME, '$Revision: 1.24 $');
1.2       andrew    571: }
                    572:

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