File Coverage

blib/lib/Mon/Client.pm
Criterion Covered Total %
statement 9 810 1.1
branch 0 362 0.0
condition 0 38 0.0
subroutine 3 63 4.7
pod 50 52 96.1
total 62 1325 4.6


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Mon::Client - Methods for interaction with Mon client
4              
5             =head1 SYNOPSIS
6              
7             use Mon::Client;
8              
9             =head1 DESCRIPTION
10              
11             Mon::Client is used to interact with "mon" clients. It supports
12             a protocol-independent API for retrieving the status of the mon
13             server, and performing certain operations, such as disableing hosts
14             and service checks.
15              
16             =head1 METHODS
17              
18             =over 4
19              
20             =item new
21              
22             Creates a new object. A hash can be supplied which sets the
23             default values. An example which contains all of the variables
24             that you can initialize:
25              
26             $c = new Mon::Client (
27             host => "monhost",
28             port => 2583,
29             username => "foo",
30             password => "bar",
31             );
32              
33             =item password (pw)
34              
35             If I is provided, sets the password. Otherwise, returns the
36             currently set password.
37              
38             =item host (host)
39              
40             If I is provided, sets the mon host. Otherwise, returns the
41             currently set mon host.
42              
43              
44             =item port (portnum)
45              
46             If I is provided, sets the mon port number. Otherwise, returns the
47             currently set port number.
48              
49              
50             =item username (user)
51              
52             If I is provided, sets the user login. Otherwise, returns the
53             currently set user login.
54              
55             =item prot
56              
57             If I is provided, sets the protocol, specified by a string
58             which is of the form "1.2.3", where "1" is the major revision, "2" is
59             the minor revision, and "3" is the sub-minor revision.
60             If I is not provided, the currently set protocol is returned.
61              
62              
63             =item protid ([protocol])
64              
65             Returns true if client and server protocol match, false otherwise.
66             Implicitly called by B. If protocol is specified as an integer,
67             supplies that protocol version to the server for verification.
68              
69              
70             =item version
71              
72             Returns the protocol version of the remote server.
73              
74             =item error
75              
76             Returns the error string from set by the last method, or undef if
77             there was no error.
78              
79             =item connected
80              
81             Returns 0 (not connected) or 1 (connected).
82              
83             =item connect (%args)
84              
85             Connects to the server. If B and B have not been set,
86             uses the defaults. Returns I on error. If $args{"skip_protid"}
87             is true, skip protocol identification upon connect.
88              
89             =item disconnect
90              
91             Disconnects from the server. Return I on error.
92              
93             =item login ( %hash )
94              
95             B<%hash> is optional, but if specified, should contain two keys,
96             B and B.
97              
98             Performs the "login" command to authenticate the user to the server.
99             Uses B and B if specified, otherwise uses
100             the username and password previously set by those methods, respectively.
101              
102              
103             =item checkauth ( command )
104              
105             Checks to see if the specified command, as executed by the current user,
106             is authorized by the server, without actually executing the command.
107             Returns 1 (command is authorized) or 0 (command is not authorized).
108              
109              
110             =item disable_watch ( watch )
111              
112             Disables B.
113              
114             =item disable_service ( watch, service )
115              
116             Disables a service, as specified by B and B.
117              
118              
119             =item disable_host ( host )
120              
121             Disables B.
122              
123             =item enable_watch ( watch )
124              
125             Enables B.
126              
127             =item enable_service ( watch, service )
128              
129             Enables a service as specified by B and B.
130              
131             =item enable_host ( host )
132              
133             Enables B.
134              
135             =item set ( group, service, var, val )
136              
137             Sets B in B to B. Returns
138             undef on error.
139              
140             =item get ( group, service, var )
141              
142             Gets variable B in B and returns it,
143             or undef on error.
144              
145             =item quit
146              
147             Logs out of the server. This method should be followed
148             by a call to the B method.
149              
150             =item list_descriptions
151              
152             Returns a hash of service descriptions, indexed by watch
153             and service. For example:
154              
155             %desc = $mon->list_descriptions;
156             print "$desc{'watchname'}->{'servicename'}\n";
157              
158             =item list_deps
159              
160             Lists dependency expressions and their components for all
161             services. If there is no dependency for a particular service,
162             then the value will be "NONE".
163              
164             %deps = $mon->list_deps;
165             foreach $watch (keys %deps) {
166             foreach $service (keys %{$deps{$watch}}) {
167             my $sref = \%{$deps{$watch}->{$service}};
168             print "expr ($watch,$service) = $sref->{expression}\n";
169             print "components ($watch,$service) = @{$sref->{components}}\n";
170             }
171             }
172              
173             =item list_group ( hostgroup )
174              
175             Lists members of B. Returns an array of each
176             member.
177              
178             =item list_watch
179              
180             Returns an array of all the defined watch groups and services.
181              
182             foreach $w ($mon->list_watch) {
183             print "group=$w->[0] service=$w->[1]\n";
184             }
185              
186             =item list_opstatus ( [group1, service1], ... )
187              
188             Returns a hash of per-service operational statuses, as indexed by watch
189             and service. The list of anonymous arrays is optional, and if is not
190             provided then the status of all groups and services will be queried.
191              
192             %s = $mon->list_opstatus;
193             foreach $watch (keys %s) {
194             foreach $service (keys %{$s{$watch}}) {
195             foreach $var (keys %{$s{$watch}{$service}}) {
196             print "$watch $service $var=$s{$watch}{$service}{$var}\n";
197             }
198             }
199             }
200              
201             =item list_failures
202              
203             Returns a hash in the same manner as B, but only
204             the services which are in a failure state.
205              
206             =item list_successes
207              
208             Returns a hash in the same manner as B, but only
209             the services which are in a success state.
210              
211             =item list_disabled
212              
213             Returns a hash of disabled watches, services, and hosts.
214              
215             %d = $mon->list_disabled;
216              
217             foreach $group (keys %{$d{"hosts"}}) {
218             foreach $host (keys %{$d{"hosts"}{$group}}) {
219             print "host $group/$host disabled\n";
220             }
221             }
222              
223             foreach $watch (keys %{$d{"services"}}) {
224             foreach $service (keys %{$d{"services"}{$watch}}) {
225             print "service $watch/$service disabled\n";
226             }
227             }
228              
229             for (keys %{$d{"watches"}}) {
230             print "watch $_ disabled\n";
231             }
232              
233             =item list_alerthist
234              
235             Returns an array of hash references containing the alert history.
236              
237             @a = $mon->list_alerthist;
238              
239             for (@a) {
240             print join (" ",
241             $_->{"type"},
242             $_->{"watch"},
243             $_->{"service"},
244             $_->{"time"},
245             $_->{"alert"},
246             $_->{"args"},
247             $_->{"summary"},
248             "\n",
249             );
250             }
251              
252             =item list_dtlog
253              
254             Returns an array of hash references containing the downtime log.
255              
256             @a = $mon->list_dtlog
257              
258             for (@a) {
259             print join (" ",
260             $_->{"timeup"},
261             $_->{"group"},
262             $_->{"service"},
263             $_->{"failtime"},
264             $_->{"downtime"},
265             $_->{"interval"},
266             $_->{"summary"},
267             "\n",
268             );
269             }
270              
271             =item list_failurehist
272              
273             Returns an array of hash references containing the failure history.
274              
275             @f = $mon->list_failurehist;
276              
277             for (@f) {
278             print join (" ",
279             $_->{"watch"},
280             $_->{"service"},
281             $_->{"time"},
282             $_->{"summary"},
283             "\n",
284             );
285             }
286              
287             =item list_pids
288              
289             Returns an array of hash references containing the list of process IDs
290             of currently active monitors run by the server.
291              
292             @p = $mon->list_pids;
293              
294             $server = shift @p;
295              
296             for (@p) {
297             print join (" ",
298             $_->{"watch"},
299             $_->{"service"},
300             $_->{"pid"},
301             "\n",
302             );
303             }
304              
305             =item list_state
306              
307             Lists the state of the scheduler. Returns a two-element array. The
308             first element of the array is 0 if the scheduler is stopped, and 1
309             if the scheduler is currently running. The second element of the array
310             returned is the string "scheduler running" if the scheduler is
311             currently running, and if the scheduler is stopped, the second
312             element is the time(2) that the scheduler was stopped.
313              
314             @s = $mon->list_state;
315              
316             if ($s[0] == 0) {
317             print "scheduler stopped since " . localtime ($s[1]) . "\n";
318             }
319              
320             =item start
321              
322             Starts the scheduler.
323              
324             =item stop
325              
326             Stops the scheduler.
327              
328             =item reset
329              
330             Resets the server.
331              
332             =item reload ( what )
333              
334             Causes the server to reload its configuration. B is an optional
335             argument, and currently the only supported option is B, which
336             reloads the authorization file.
337              
338             =item term
339              
340             Terminates the server.
341              
342             =item set_maxkeep
343              
344             Sets the maximum number of history entries to store in memory.
345              
346             =item get_maxkeep
347              
348             Returns the maximum number of history entries to store in memory.
349              
350             =item test ( test, group, service [, exitval, period])
351              
352             Schedules a service test to run immediately, or tests an alert for a
353             given period. B must be B, B, B, or
354             B. To test alerts, the B and B must be supplied.
355             Periods are identified by their label in the mon config file. If there
356             are no period tags, then the actual period string must be used, exactly
357             as it is listed in the config file.
358              
359             =item test_config
360              
361             Tests the syntax of the configuration file. Returns a two-element
362             array. The first element of the array is 0 if the syntax of the
363             config file is invalid, and 1 if the syntax of the config file
364             is OK. The second element of the array returned is the failure
365             message, if the config file has invalid syntax, and the result code
366             if the config file syntax is OK. This function returns undef if it
367             cannot get a connection or a response from the mon server.
368              
369             Config file checking stops as soon as an error is found, so
370             you will need to run this command more than once if you have multiple
371             errors in your config file in order to find them all.
372              
373             @s = $mon->test_config;
374              
375             if ($s[0] == 0) {
376             print "error in config file:\n" . $s[1] . "\n";
377             }
378              
379              
380             =item ack ( group, service, text )
381              
382             When B is in a failure state,
383             acknowledges this with B, and disables all further
384             alerts during this failure period.
385              
386             =item loadstate ( state )
387              
388             Loads B.
389              
390             =item savestate ( state )
391              
392             Saves B.
393              
394             =item servertime
395              
396             Returns the time on the server using the same output as the
397             time(2) system call.
398              
399             =item send_trap ( %vars )
400              
401             Sends a trap to a remote mon server. Here is an example:
402              
403             $mon->send_trap (
404             group => "remote-group",
405             service => "remote-service",
406             retval => 1,
407             opstatus => "operational status",
408             summary => "summary line",
409             detail => "multi-line detailed information",
410             );
411              
412             I must be a nonnegative integer.
413              
414             I must be one of I, I, I, I,
415             I, I, I, I.
416              
417             Returns I on error.
418              
419             =back
420              
421             =cut
422             #
423             # Perl module for interacting with a mon server
424             #
425             # $Id: Client.pm 1.4 Thu, 11 Jan 2001 08:42:17 -0800 trockij $
426             #
427             # Copyright (C) 1998-2000 Jim Trocki
428             #
429             # This program is free software; you can redistribute it and/or modify
430             # it under the terms of the GNU General Public License as published by
431             # the Free Software Foundation; either version 2 of the License, or
432             # (at your option) any later version.
433             #
434             # This program is distributed in the hope that it will be useful,
435             # but WITHOUT ANY WARRANTY; without even the implied warranty of
436             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
437             # GNU General Public License for more details.
438             #
439             # You should have received a copy of the GNU General Public License
440             # along with this program; if not, write to the Free Software
441             # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
442             #
443             #
444              
445             package Mon::Client;
446             require Exporter;
447             require 5.004;
448 1     1   19567 use IO::File;
  1         3  
  1         177  
449 1     1   6 use Socket;
  1         2  
  1         701  
450 1     1   6 use Text::ParseWords;
  1         3  
  1         11351  
451              
452             @ISA = qw(Exporter);
453             @EXPORT_OK = qw(%OPSTAT $VERSION);
454              
455             $VERSION = "0.11";
456              
457             my ($STAT_FAIL, $STAT_OK, $STAT_COLDSTART, $STAT_WARMSTART, $STAT_LINKDOWN,
458             $STAT_UNKNOWN, $STAT_TIMEOUT, $STAT_UNTESTED, $STAT_DEPEND, $STAT_WARN) = (0..9);
459              
460             my ($TRAP_COLDSTART, $TRAP_WARMSTART, $TRAP_LINKDOWN, $TRAP_LINKUP,
461             $TRAP_AUTHFAIL, $TRAP_EGPNEIGHBORLOSS, $TRAP_ENTERPRISE, $TRAP_HEARTBEAT) = (0..7);
462            
463             %OPSTAT = ("fail" => $STAT_FAIL, "ok" => $STAT_OK, "coldstart" =>
464             $STAT_COLDSTART, "warmstart" => $STAT_WARMSTART, "linkdown" =>
465             $STAT_LINKDOWN, "unknown" => $STAT_UNKNOWN, "timeout" => $STAT_TIMEOUT,
466             "untested" => $STAT_UNTESTED, "dependency" => $STAT_DEPEND);
467              
468             my %TRAPS = ( "coldstart" => $TRAP_COLDSTART, "warmstart" =>
469             $TRAP_WARMSTART, "linkdown" => $TRAP_LINKDOWN, "linkup" => $TRAP_LINKUP,
470             "authfail" => $TRAP_AUTHFAIL, "egpneighborloss" => $TRAP_EGPNEIGHBORLOSS,
471             "enterprise" => $TRAP_ENTERPRISE, "heartbeat" => $TRAP_HEARTBEAT );
472              
473              
474              
475             sub _sock_write;
476             sub _sock_readline;
477             sub _do_cmd;
478             sub _list_opstatus;
479             sub _start_stop;
480             sub _un_esc_str;
481             sub _esc_str;
482              
483             sub new {
484 0     0 1   my $proto = shift;
485 0   0       my $class = ref($proto) || $proto;
486 0           my $self = {};
487 0           my %vars = @_;
488              
489 0 0         if ($ENV{"MONHOST"}) {
490 0           $self->{"HOST"} = $ENV{"MONHOST"};
491             } else {
492 0           $self->{"HOST"} = undef;
493             }
494              
495 0           $self->{"CONNECTED"} = undef;
496 0           $self->{"HANDLE"} = new IO::File;
497              
498 0   0       $self->{"PORT"} = getservbyname ("mon", "tcp") || 2583;
499 0           $self->{"PROT"} = 0x2611;
500 0           $self->{"TRAP_PRO_VERSION"} = "0.3807";
501 0           $self->{"PASSWORD"} = undef;
502 0           $self->{"USERNAME"} = undef;
503 0           $self->{"DESCRIPTIONS"} = undef;
504 0           $self->{"GROUPS"} = undef;
505 0           $self->{"ERROR"} = undef;
506 0           $self->{"VERSION"} = undef;
507              
508 0 0         if ($ENV{"USER"} ne "") {
509 0           $self->{"USERNAME"} = $ENV{"USER"};
510             } else {
511 0           $self->{"USERNAME"} = (getpwuid ($<))[0];
512             }
513              
514 0           $self->{"OPSTATUS"} = undef;
515 0           $self->{"DISABLED"} = undef;
516              
517 0           foreach my $k (keys %vars) {
518 0 0 0       if ($k eq "host" && $vars{$k} ne "") {
    0 0        
    0          
    0          
519 0           $self->{"HOST"} = $vars{$k};
520             } elsif ($k eq "port" && $vars{$k} ne "") {
521 0           $self->{"PORT"} = $vars{$k};
522             } elsif ($k eq "username") {
523 0           $self->{"USERNAME"} = $vars{$k};
524             } elsif ($k eq "password") {
525 0           $self->{"PASSWORD"} = $vars{$k};
526             }
527             }
528              
529 0           bless ($self, $class);
530 0           return $self;
531             }
532              
533             sub password {
534 0     0 1   my $self = shift;
535 0 0         if (@_) { $self->{"PASSWORD"} = shift }
  0            
536 0           return $self->{"PASSWORD"};
537             }
538              
539             sub host {
540 0     0 1   my $self = shift;
541 0 0         if (@_) { $self->{"HOST"} = shift }
  0            
542 0           return $self->{"HOST"};
543             }
544              
545             sub port {
546 0     0 1   my $self = shift;
547 0 0         if (@_) { $self->{"PORT"} = shift }
  0            
548 0           return $self->{"PORT"};
549             }
550              
551             sub username {
552 0     0 1   my $self = shift;
553 0 0         if (@_) { $self->{"USERNAME"} = shift }
  0            
554 0           return $self->{"USERNAME"};
555             }
556              
557              
558             sub prot {
559 0     0 1   my $self = shift;
560              
561 0           undef $self->{"ERROR"};
562              
563 0 0         if (@_) {
564 0 0         if ($_[0] =~ /^\d+\.\d+\.\d+$/) {
565 0           $self->{"PROT"} = shift;
566             } else {
567 0           $self->{"ERROR"} = "invalid protocol version";
568 0           return undef;
569             }
570             }
571 0           return $self->{"PROT"};
572             }
573              
574              
575             sub DESTROY {
576 0     0     my $self = shift;
577              
578 0 0         if ($self->{"CONNECTED"}) { $self->disconnect; }
  0            
579             }
580              
581             sub error {
582 0     0 1   my $self = shift;
583              
584 0           return $self->{"ERROR"};
585             }
586              
587             sub connected {
588 0     0 1   my $self = shift;
589              
590 0           return $self->{"CONNECTED"};
591             }
592              
593              
594             sub connect {
595 0     0 1   my $self = shift;
596 0           my %args = @_;
597              
598 0           my ($iaddr, $paddr, $proto);
599              
600 0           undef $self->{"ERROR"};
601              
602 0 0         if ($self->{"HOST"} eq "") {
603 0           $self->{"ERROR"} = "no host defined";
604 0           return undef;
605             }
606              
607 0 0         if (!defined ($iaddr = inet_aton ($self->{"HOST"}))) {
608 0           $self->{"ERROR"} = "could not resolve host";
609 0           return undef;
610             }
611              
612 0 0         if (!defined ($paddr = sockaddr_in ($self->{"PORT"}, $iaddr))) {
613 0           $self->{"ERROR"} = "could not generate sockaddr";
614 0           return undef;
615             }
616              
617 0 0         if (!defined ($proto = getprotobyname ('tcp'))) {
618 0           $self->{"ERROR"} = "could not getprotobyname for tcp";
619 0           return undef;
620             }
621              
622 0 0         if (!defined socket ($self->{"HANDLE"}, PF_INET, SOCK_STREAM, $proto)) {
623 0           $self->{"ERROR"} = "socket failed, $!";
624 0           return undef;
625             }
626              
627 0 0         if (!defined connect ($self->{"HANDLE"}, $paddr)) {
628 0           $self->{"ERROR"} = "connect failed, $!";
629 0           return undef;
630             }
631              
632 0           $self->{"CONNECTED"} = 1;
633              
634 0 0         if (!$args{"skip_protid"})
635             {
636 0 0         if (!$self->protid)
637             {
638 0           $self->{"ERROR"} = "connect failed, protocol mismatch";
639 0           close ($self->{"HANDLE"});
640 0           return undef;
641             }
642             }
643              
644 0           1;
645             }
646              
647              
648             sub protid {
649 0     0 1   my $self = shift;
650 0           my $p = shift;
651              
652 0           undef $self->{"ERROR"};
653              
654 0 0         if (!$self->{"CONNECTED"}) {
655 0           $self->{"ERROR"} = "not connected";
656 0           return undef;
657             }
658              
659 0 0         if (!defined $p) {
660 0           $p = int ($self->{"PROT"});
661             }
662              
663 0           my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "protid $p");
664              
665 0 0         if (!defined $r) {
    0          
666 0           $self->{"ERROR"} = "error ($l)";
667 0           return undef;
668             } elsif ($r !~ /^220/) {
669 0           $self->{"ERROR"} = $r;
670 0           return undef;
671             }
672              
673 0           1;
674             }
675              
676             sub disconnect {
677 0     0 1   my $self = shift;
678              
679 0           undef $self->{"ERROR"};
680              
681 0 0         if (!defined close ($self->{"HANDLE"})) {
682 0           $self->{"ERROR"} = "could not close: $!";
683 0           return undef;
684             }
685              
686 0           $self->{"CONNECTED"} = 0;
687              
688 0           return 1;
689             }
690              
691              
692             sub login {
693 0     0 1   my $self = shift;
694 0           my %l = @_;
695              
696 0           undef $self->{"ERROR"};
697              
698 0 0         $self->{"USERNAME"} = $l{"username"} if (defined $l{"username"});
699 0 0         $self->{"PASSWORD"} = $l{"password"} if (defined $l{"password"});
700              
701 0 0         if (!$self->{"CONNECTED"}) {
702 0           $self->{"ERROR"} = "not connected";
703 0           return undef;
704             }
705              
706 0 0 0       if (!defined $self->{"USERNAME"} || $self->{"USERNAME"} eq "") {
707 0           $self->{"ERROR"} = "no username";
708 0           return undef;
709             }
710              
711 0 0 0       if (!defined $self->{"PASSWORD"} || $self->{"PASSWORD"} eq "") {
712 0           $self->{"ERROR"} = "no password";
713 0           return undef;
714             }
715              
716 0           my ($r, $l) = _do_cmd ($self->{"HANDLE"},
717             "login $self->{USERNAME} $self->{PASSWORD}");
718              
719 0 0         if (!defined $r) {
    0          
720 0           $self->{"ERROR"} = "error ($l)";
721 0           return undef;
722             } elsif ($r !~ /^220/) {
723 0           $self->{"ERROR"} = $r;
724 0           return undef;
725             }
726              
727 0           return 1;
728             }
729              
730              
731             sub checkauth {
732 0     0 1   my $self = shift;
733 0           my ($cmd) = @_;
734              
735 0           undef $self->{"ERROR"};
736              
737 0 0         if (!$self->{"CONNECTED"}) {
738 0           $self->{"ERROR"} = "not connected";
739 0           return undef;
740             }
741              
742 0 0         if ($cmd eq "") {
743 0           $self->{"ERROR"} = "invalid command";
744 0           return undef;
745             }
746              
747 0           my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "checkauth $cmd");
748              
749 0 0         if ($r =~ /^220/) {
750 0           return 1;
751             } else {
752 0           $self->{"ERROR"} = $r;
753 0           return 0;
754             }
755             }
756              
757              
758             sub disable_watch {
759 0     0 1   my $self = shift;
760 0           my ($watch) = @_;
761              
762 0           undef $self->{"ERROR"};
763              
764 0 0         if (!$self->{"CONNECTED"}) {
765 0           $self->{"ERROR"} = "not connected";
766 0           return undef;
767             }
768              
769 0 0         if ($watch !~ /\S+/) {
770 0           $self->{"ERROR"} = "invalid watch";
771 0           return undef;
772             }
773              
774 0           my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "disable watch $watch");
775              
776 0 0         if (!defined $r) {
    0          
777 0           $self->{"ERROR"} = "error ($l)";
778 0           return undef;
779             } elsif ($r !~ /^220/) {
780 0           $self->{"ERROR"} = $r;
781 0           return undef;
782             }
783              
784 0           return $r;
785             }
786              
787              
788             sub disable_service {
789 0     0 1   my $self = shift;
790 0           my ($watch, $service) = @_;
791              
792 0           undef $self->{"ERROR"};
793              
794 0 0         if (!$self->{"CONNECTED"}) {
795 0           $self->{"ERROR"} = "not connected";
796 0           return undef;
797             }
798              
799 0 0         if ($watch !~ /\S+/) {
800 0           $self->{"ERROR"} = "invalid watch";
801 0           return undef;
802             }
803              
804 0 0         if ($service !~ /\S+/) {
805 0           $self->{"ERROR"} = "invalid service";
806 0           return undef;
807             }
808              
809 0           my ($r, $l) = _do_cmd ($self->{"HANDLE"},
810             "disable service $watch $service");
811              
812 0 0         if (!defined $r) {
    0          
813 0           $self->{"ERROR"} = "error ($l)";
814 0           return undef;
815             } elsif ($r !~ /^220/) {
816 0           $self->{"ERROR"} = $r;
817 0           return undef;
818             }
819              
820 0           return $r;
821             }
822              
823              
824             sub disable_host {
825 0     0 1   my $self = shift;
826 0           my (@hosts) = @_;
827              
828 0           undef $self->{"ERROR"};
829              
830 0 0         if (!$self->{"CONNECTED"}) {
831 0           $self->{"ERROR"} = "not connected";
832 0           return undef;
833             }
834              
835 0           my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "disable host @hosts");
836              
837 0 0         if (!defined $r) {
    0          
838 0           $self->{"ERROR"} = "error ($l)";
839 0           return undef;
840             } elsif ($r !~ /^220/) {
841 0           $self->{"ERROR"} = $r;
842 0           return undef;
843             }
844              
845 0           return $r;
846             }
847              
848              
849             sub enable_watch {
850 0     0 1   my $self = shift;
851 0           my ($watch) = @_;
852              
853 0           undef $self->{"ERROR"};
854              
855 0 0         if (!$self->{"CONNECTED"}) {
856 0           $self->{"ERROR"} = "not connected";
857 0           return undef;
858             }
859              
860 0 0         if ($watch !~ /\S+/) {
861 0           $self->{"ERROR"} = "invalid watch";
862 0           return undef;
863             }
864              
865 0           my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "enable watch $watch");
866              
867 0 0         if (!defined $r) {
    0          
868 0           $self->{"ERROR"} = "error ($l)";
869 0           return undef;
870             } elsif ($r !~ /^220/) {
871 0           $self->{"ERROR"} = $r;
872 0           return undef;
873             }
874              
875 0           return $r;
876             }
877              
878              
879             sub enable_service {
880 0     0 1   my $self = shift;
881 0           my ($watch, $service) = @_;
882              
883 0           undef $self->{"ERROR"};
884              
885 0 0         if (!$self->{"CONNECTED"}) {
886 0           $self->{"ERROR"} = "not connected";
887 0           return undef;
888             }
889              
890 0 0         if ($watch !~ /\S+/) {
891 0           $self->{"ERROR"} = "invalid watch";
892 0           return undef;
893             }
894              
895 0 0         if ($service !~ /\S+/) {
896 0           $self->{"ERROR"} = "invalid service";
897 0           return undef;
898             }
899              
900 0           my ($r, $l) = _do_cmd ($self->{"HANDLE"},
901             "enable service $watch $service");
902              
903 0 0         if (!defined $r) {
    0          
904 0           $self->{"ERROR"} = "error ($l)";
905 0           return undef;
906             } elsif ($r !~ /^220/) {
907 0           $self->{"ERROR"} = $r;
908 0           return undef;
909             }
910              
911 0           return $r;
912             }
913              
914              
915             sub enable_host {
916 0     0 1   my $self = shift;
917 0           my (@hosts) = @_;
918              
919 0           undef $self->{"ERROR"};
920              
921 0 0         if (!$self->{"CONNECTED"}) {
922 0           $self->{"ERROR"} = "not connected";
923 0           return undef;
924             }
925              
926 0           my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "enable host @hosts");
927              
928 0 0         if (!defined $r) {
    0          
929 0           $self->{"ERROR"} = "error ($l)";
930 0           return undef;
931             } elsif ($r !~ /^220/) {
932 0           $self->{"ERROR"} = $r;
933 0           return undef;
934             }
935              
936 0           return $r;
937             }
938              
939              
940             sub version {
941 0     0 1   my $self = shift;
942              
943 0           undef $self->{"ERROR"};
944              
945 0 0         if (!$self->{"CONNECTED"}) {
946 0           $self->{"ERROR"} = "not connected";
947 0           return undef;
948             }
949              
950 0 0         unless (defined($self->{"VERSION"})) {
951 0           my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "version");
952              
953 0 0         if (!defined $r) {
    0          
954 0           $self->{"ERROR"} = "error ($l)";
955 0           return undef;
956             } elsif ($r !~ /^220/) {
957 0           $self->{"ERROR"} = $r;
958 0           return undef;
959             }
960 0           ($self->{"VERSION"} = $l) =~ s/^version\s+//;;
961             }
962              
963 0           return $self->{"VERSION"};
964             }
965              
966              
967             sub quit {
968 0     0 1   my $self = shift;
969              
970 0           undef $self->{"ERROR"};
971              
972 0 0         if (!$self->{"CONNECTED"}) {
973 0           $self->{"ERROR"} = "not connected";
974 0           return undef;
975             }
976              
977 0           my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "quit");
978              
979 0           return $r;
980             }
981              
982              
983             sub list_descriptions {
984 0     0 1   my $self = shift;
985 0           my ($d, $group, $service, $desc, %desc);
986              
987 0           undef $self->{"ERROR"};
988              
989 0 0         if (!$self->{"CONNECTED"}) {
990 0           $self->{"ERROR"} = "not connected";
991 0           return undef;
992             }
993              
994 0           my ($r, @d) = _do_cmd ($self->{"HANDLE"}, "list descriptions");
995              
996 0 0         if (!defined $r) {
    0          
997 0           $self->{"ERROR"} = "error (@d)";
998 0           return undef;
999             } elsif ($r !~ /^220/) {
1000 0           $self->{"ERROR"} = $r;
1001 0           return undef;
1002             }
1003              
1004 0 0         return $r if (!defined $r);
1005              
1006 0           foreach $d (@d) {
1007 0           ($group, $service, $desc) = split (/\s+/, $d, 3);
1008 0           $desc{$group}{$service} =
1009             _un_esc_str ((parse_line ('\s+', 0, $desc))[0]);
1010             }
1011              
1012 0           return %desc;
1013             }
1014              
1015              
1016             sub list_deps {
1017 0     0 1   my $self = shift;
1018              
1019 0           undef $self->{"ERROR"};
1020              
1021 0 0         if (!$self->{"CONNECTED"}) {
1022 0           $self->{"ERROR"} = "not connected";
1023 0           return undef;
1024             }
1025              
1026 0           my ($r, @d) = _do_cmd ($self->{"HANDLE"}, "list deps");
1027              
1028 0 0         if (!defined $r) {
    0          
1029 0           $self->{"ERROR"} = "error (@d)";
1030 0           return undef;
1031             } elsif ($r !~ /^220/) {
1032 0           $self->{"ERROR"} = $r;
1033 0           return undef;
1034             }
1035              
1036 0 0         return $r if (!defined $r);
1037              
1038 0           my %dep = ();
1039              
1040 0           foreach my $d (@d) {
1041 0           my ($what, $group, $service, $l) = split (/\s+/, $d, 4);
1042              
1043 0 0         if ($what eq "exp") {
    0          
1044 0           $dep{$group}->{$service}->{"expression"} =
1045             _un_esc_str ((parse_line ('\s+', 0, $l))[0]);
1046              
1047             } elsif ($what eq "cmp") {
1048 0           @{$dep{$group}->{$service}->{"components"}} =
  0            
1049             split (/\s+/, $l);
1050             }
1051             }
1052              
1053 0           return %dep;
1054             }
1055              
1056              
1057             sub list_group {
1058 0     0 1   my $self = shift;
1059 0           my ($group) = @_;
1060              
1061 0           undef $self->{"ERROR"};
1062              
1063 0 0         if (!$self->{"CONNECTED"}) {
1064 0           $self->{"ERROR"} = "not connected";
1065 0           return undef;
1066             }
1067              
1068 0 0         if ($group eq "") {
1069 0           $self->{"ERROR"} = "invalid group";
1070 0           return undef;
1071             }
1072              
1073 0           my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "list group $group");
1074              
1075 0 0         if ($r =~ /^220/) {
1076 0           $l =~ s/^hostgroup\s+$group\s+//;;
1077 0           return split (/\s+/, $l);
1078             } else {
1079 0           $self->{"ERROR"} = $l;
1080 0           return undef;
1081             }
1082              
1083             }
1084              
1085              
1086             sub list_watch {
1087 0     0 1   my $self = shift;
1088              
1089 0           undef $self->{"ERROR"};
1090              
1091 0 0         if (!$self->{"CONNECTED"}) {
1092 0           $self->{"ERROR"} = "not connected";
1093 0           return undef;
1094             }
1095              
1096 0           my ($r, @l) = _do_cmd ($self->{"HANDLE"}, "list watch");
1097              
1098 0           my @groups;
1099              
1100 0 0         if ($r =~ /^220/)
1101             {
1102 0           foreach my $l (@l)
1103             {
1104 0           push @groups, [split (/\s+/, $l, 2)];
1105             }
1106 0           @groups;
1107             }
1108            
1109             else
1110             {
1111 0           $self->{"ERROR"} = $l;
1112 0           return undef;
1113             }
1114             }
1115              
1116              
1117             sub list_opstatus {
1118 0     0 1   my $self = shift;
1119 0           my @g = @_;
1120              
1121 0 0         if (@g == 0)
1122             {
1123 0           _list_opstatus ($self, "list opstatus");
1124             }
1125              
1126             else
1127             {
1128 0           my @l;
1129 0           foreach my $i (@g)
1130             {
1131 0           push @l, "$i->[0],$i->[1]";
1132             }
1133 0           _list_opstatus ($self, "list opstatus " . join (" ", @l));
1134             }
1135             }
1136              
1137              
1138             sub list_failures {
1139 0     0 1   my $self = shift;
1140              
1141 0           _list_opstatus($self, "list failures");
1142             }
1143              
1144              
1145             sub list_successes {
1146 0     0 1   my $self = shift;
1147              
1148 0           _list_opstatus($self, "list successes");
1149             }
1150              
1151              
1152             sub list_disabled {
1153 0     0 1   my $self = shift;
1154 0           my (%disabled, $h);
1155              
1156 0           undef $self->{"ERROR"};
1157              
1158 0 0         if (!$self->{"CONNECTED"}) {
1159 0           $self->{"ERROR"} = "not connected";
1160 0           return undef;
1161             }
1162              
1163 0           my ($r, @d) = _do_cmd ($self->{"HANDLE"}, "list disabled");
1164              
1165 0 0         if (!defined $r) {
    0          
1166 0           $self->{"ERROR"} = $d[0];
1167 0           return undef;
1168             } elsif ($r !~ /^220/) {
1169 0           $self->{"ERROR"} = $r;
1170 0           return undef;
1171             }
1172              
1173 0           foreach $r (@d) {
1174 0 0         if ($r =~ /^group (\S+): (.*)$/) {
    0          
    0          
1175 0           foreach $h (split (/\s+/, $2)) {
1176 0           $disabled{hosts}{$1}{$h} = 1;
1177             }
1178              
1179             } elsif ($r =~ /^watch (\S+) service (\S+)$/) {
1180 0           $disabled{services}{$1}{$2} = 1;
1181              
1182             } elsif ($r =~ /^watch (\S+)/) {
1183 0           $disabled{watches}{$1} = 1;
1184              
1185             } else {
1186 0           next;
1187             }
1188             }
1189              
1190 0           return %disabled;
1191             }
1192              
1193              
1194             sub list_alerthist {
1195 0     0 1   my $self = shift;
1196 0           my (@alerts, $h, $group, $service, $time, $alert, $args, $summary);
1197              
1198 0           undef $self->{"ERROR"};
1199              
1200 0 0         if (!$self->{"CONNECTED"}) {
1201 0           $self->{"ERROR"} = "not connected";
1202 0           return undef;
1203             }
1204              
1205 0           my ($r, @h) = _do_cmd ($self->{"HANDLE"}, "list alerthist");
1206              
1207 0 0         if (!defined $r) {
    0          
1208 0           $self->{"ERROR"} = "error (@h)";
1209 0           return undef;
1210             } elsif ($r !~ /^220/) {
1211 0           $self->{"ERROR"} = $r;
1212 0           return undef;
1213             }
1214              
1215 0           foreach $h (@h) {
1216 0           $h = _un_esc_str ($h);
1217 0           my ($type, $group, $service, $time, $alert, $args, $summary) =
1218             ($h =~ /^(\S+) \s+ (\S+) \s+ (\S+) \s+
1219             (\d+) \s+ (\S+) \s+ \(([^)]*)\) \s+ (.*)$/x);
1220 0           push @alerts, { type => $type,
1221             watch => $group,
1222             group => $group,
1223             service => $service,
1224             time => $time,
1225             alert => $alert,
1226             args => $args,
1227             summary => $summary };
1228             }
1229              
1230 0           return @alerts;
1231             }
1232              
1233              
1234             sub list_dtlog {
1235 0     0 1   my $self = shift;
1236 0           my (@dtlog, $h, $timeup, $group, $service, $failtime, $downtime, $interval, $summary);
1237              
1238 0           undef $self->{"ERROR"};
1239              
1240 0 0         if (!$self->{"CONNECTED"}) {
1241 0           $self->{"ERROR"} = "not connected";
1242 0           return undef;
1243             }
1244              
1245 0           my ($r, @h) = _do_cmd ($self->{"HANDLE"}, "list dtlog");
1246              
1247 0 0         if (!defined $r) {
    0          
1248 0           $self->{"ERROR"} = "error (@h)";
1249 0           return undef;
1250             } elsif ($r !~ /^220/) {
1251 0           $self->{"ERROR"} = $r;
1252 0           return undef;
1253             }
1254              
1255 0           foreach $h (@h) {
1256 0           $h = _un_esc_str ($h);
1257              
1258 0           my ($timeup, $group, $service, $failtime, $downtime, $interval, $summary) =
1259             ($h =~ /^(\d+) \s+ (\S+) \s+ (\S+) \s+
1260             (\d+) \s+ (\d+) \s+ (\d+) \s+ (.*)$/x);
1261              
1262 0           push @dtlog, { timeup => $timeup,
1263             group => $group,
1264             service => $service,
1265             failtime => $failtime,
1266             downtime => $downtime,
1267             interval => $interval,
1268             summary => $summary };
1269             }
1270              
1271 0           return @dtlog;
1272             }
1273              
1274              
1275             sub list_failurehist {
1276 0     0 1   my $self = shift;
1277 0           my ($r, @f, $f, $group, $service, $time, $summary, @failures);
1278              
1279 0           undef $self->{"ERROR"};
1280              
1281 0 0         if (!$self->{"CONNECTED"}) {
1282 0           $self->{"ERROR"} = "not connected";
1283 0           return undef;
1284             }
1285              
1286 0           ($r, @f) = _do_cmd ($self->{"HANDLE"}, "list failurehist");
1287              
1288 0 0         if (!defined $r) {
    0          
1289 0           $self->{"ERROR"} = "@f";
1290 0           return undef;
1291             } elsif ($r !~ /^220/) {
1292 0           $self->{"ERROR"} = $r;
1293 0           return undef;
1294             }
1295              
1296 0           foreach $f (@f) {
1297 0           ($group, $service, $time, $summary) = split (/\s+/, $f, 4);
1298 0           push @failures, {
1299             watch => $group,
1300             service => $service,
1301             time => $time,
1302             summary => $summary
1303             };
1304             }
1305              
1306 0           return @failures;
1307             }
1308              
1309              
1310             sub list_pids {
1311 0     0 1   my $self = shift;
1312 0           my ($r, $l, @pids, @p, $p, $pid, $group, $service, $server);
1313              
1314 0           undef $self->{"ERROR"};
1315              
1316 0 0         if (!$self->{"CONNECTED"}) {
1317 0           $self->{"ERROR"} = "not connected";
1318 0           return undef;
1319             }
1320              
1321 0           ($r, @p) = _do_cmd ($self->{"HANDLE"}, "list pids");
1322              
1323 0 0         if (!defined $r) {
    0          
1324 0           $self->{"ERROR"} = "@p";
1325 0           return undef;
1326             } elsif ($r !~ /^220/) {
1327 0           $self->{"ERROR"} = $r;
1328 0           return undef;
1329             }
1330              
1331 0           foreach $p (@p) {
1332 0 0         if ($p =~ /server (\d+)/) {
1333 0           $server = $1;
1334              
1335             } else {
1336 0           ($group, $service, $pid) = split (/\s+/, $p);
1337 0           push @pids, { watch => $group, service => $service, pid => $pid };
1338             }
1339             }
1340              
1341 0           return ($server, @pids);
1342             }
1343              
1344              
1345             sub list_state {
1346 0     0 1   my $self = shift;
1347 0           my ($r, $l);
1348              
1349 0           undef $self->{"ERROR"};
1350              
1351 0 0         if (!$self->{"CONNECTED"}) {
1352 0           $self->{"ERROR"} = "not connected";
1353 0           return undef;
1354             }
1355              
1356 0           ($r, $l) = _do_cmd ($self->{"HANDLE"}, "list state");
1357              
1358 0 0         if (!defined $r) {
    0          
1359 0           $self->{"ERROR"} = $l;
1360 0           return undef;
1361             } elsif ($r !~ /^220/) {
1362 0           $self->{"ERROR"} = $r;
1363 0           return undef;
1364             }
1365              
1366 0 0         if ($l =~ /scheduler running/) {
    0          
1367 0           return (1, $l);
1368             } elsif ($l =~ /scheduler stopped since (\d+)/) {
1369 0           return (0, $1);
1370             }
1371             }
1372              
1373              
1374             sub start {
1375 0     0 1   my $self = shift;
1376              
1377 0           _start_stop ($self, "start");
1378             }
1379              
1380              
1381             sub stop {
1382 0     0 1   my $self = shift;
1383              
1384 0           _start_stop ($self, "stop");
1385             }
1386              
1387              
1388             sub reset {
1389 0     0 1   my $self = shift;
1390 0           my @opts = @_;
1391 0           my ($r, $l);
1392              
1393 0           undef $self->{"ERROR"};
1394              
1395 0 0         if (!$self->{"CONNECTED"}) {
1396 0           $self->{"ERROR"} = "not connected";
1397 0           return undef;
1398             }
1399              
1400 0 0         if (@opts == 0) {
1401 0           ($r, $l) = _do_cmd ($self->{"HANDLE"}, "reset");
1402             } else {
1403 0           ($r, $l) = _do_cmd ($self->{"HANDLE"}, "reset @opts");
1404             }
1405              
1406 0 0         if (!defined $r) {
    0          
1407 0           $self->{"ERROR"} = $l;
1408 0           return undef;
1409             } elsif ($r !~ /^220/) {
1410 0           $self->{"ERROR"} = $r;
1411 0           return undef;
1412             }
1413              
1414 0           return $r;
1415             }
1416              
1417              
1418             sub reload {
1419 0     0 1   my $self = shift;
1420 0           my ($r, $l);
1421              
1422 0           undef $self->{"ERROR"};
1423              
1424 0 0         if (!$self->{"CONNECTED"}) {
1425 0           $self->{"ERROR"} = "not connected";
1426 0           return undef;
1427             }
1428              
1429 0           ($r, $l) = _do_cmd ($self->{"HANDLE"}, join (" ", "reload", @_));
1430              
1431 0 0         if (!defined $r) {
    0          
1432 0           $self->{"ERROR"} = $l;
1433 0           return undef;
1434             } elsif ($r !~ /^220/) {
1435 0           $self->{"ERROR"} = $r;
1436 0           return undef;
1437             }
1438              
1439 0           return $r;
1440             }
1441              
1442              
1443             sub term {
1444 0     0 1   my $self = shift;
1445 0           my ($r, $l);
1446              
1447 0           undef $self->{"ERROR"};
1448              
1449 0 0         if (!$self->{"CONNECTED"}) {
1450 0           $self->{"ERROR"} = "not connected";
1451 0           return undef;
1452             }
1453              
1454 0           ($r, $l) = _do_cmd ($self->{"HANDLE"}, "term");
1455              
1456 0 0         if (!defined $r) {
    0          
1457 0           $self->{"ERROR"} = $l;
1458 0           return undef;
1459             } elsif ($r !~ /^220/) {
1460 0           $self->{"ERROR"} = $r;
1461 0           return undef;
1462             }
1463              
1464 0           return $r;
1465             }
1466              
1467              
1468             sub set_maxkeep {
1469 0     0 1   my $self = shift;
1470 0           my $val = shift;
1471              
1472 0           undef $self->{"ERROR"};
1473              
1474 0 0         if (!$self->{"CONNECTED"}) {
1475 0           $self->{"ERROR"} = "not connected";
1476 0           return undef;
1477             }
1478              
1479 0 0         if ($val !~ /^\d+$/) {
1480 0           $self->{"ERROR"} = "invalid value for maxkeep";
1481 0           return undef;
1482             }
1483              
1484 0           my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "set maxkeep $val");
1485              
1486 0 0         if (!defined $r) {
    0          
1487 0           $self->{"ERROR"} = $l;
1488 0           return undef;
1489             } elsif ($r !~ /^220/) {
1490 0           $self->{"ERROR"} = $r;
1491 0           return undef;
1492             }
1493              
1494 0           return $r;
1495             }
1496              
1497              
1498             sub get_maxkeep {
1499 0     0 1   my $self = shift;
1500              
1501 0           undef $self->{"ERROR"};
1502              
1503 0 0         if (!$self->{"CONNECTED"}) {
1504 0           $self->{"ERROR"} = "not connected";
1505 0           return undef;
1506             }
1507              
1508 0           my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "set maxkeep");
1509              
1510 0 0         if (!defined $r) {
    0          
1511 0           $self->{"ERROR"} = $l;
1512 0           return undef;
1513             } elsif ($r !~ /^220/) {
1514 0           $self->{"ERROR"} = $r;
1515 0           return undef;
1516             }
1517              
1518 0           $l =~ /maxkeep = (\d+)/;
1519              
1520 0           return $1;
1521             }
1522              
1523              
1524             sub set {
1525 0     0 1   my $self = shift;
1526 0           my ($group, $service, $var, $val) = @_;
1527              
1528 0           undef $self->{"ERROR"};
1529              
1530 0 0         if (!$self->{"CONNECTED"}) {
1531 0           $self->{"ERROR"} = "not connected";
1532 0           return undef;
1533             }
1534              
1535 0           my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "set $group $service $var " .
1536             "'" . _esc_str ($val, 1) . "'");
1537              
1538 0 0         if (!defined $r)
    0          
1539             {
1540 0           $self->{"ERROR"} = $l;
1541 0           return undef;
1542             }
1543             elsif ($r !~ /^220/)
1544             {
1545 0           $self->{"ERROR"} = $r;
1546 0           return undef;
1547             }
1548              
1549 0           return $r;
1550             }
1551              
1552              
1553             sub get {
1554 0     0 1   my $self = shift;
1555 0           my ($group, $service, $var) = @_;
1556              
1557 0           undef $self->{"ERROR"};
1558              
1559 0 0         if (!$self->{"CONNECTED"}) {
1560 0           $self->{"ERROR"} = "not connected";
1561 0           return undef;
1562             }
1563              
1564 0           my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "get $group $service $var");
1565              
1566 0 0         if (!defined $r) {
    0          
1567 0           $self->{"ERROR"} = $l;
1568 0           return undef;
1569             } elsif ($r !~ /^220/) {
1570 0           $self->{"ERROR"} = $r;
1571 0           return undef;
1572             }
1573              
1574 0           ($group, $service, $var) = split (/\s+/, $l, 3);
1575 0           $var =~ s/^[^=]*=//;
1576              
1577 0           return _un_esc_str ((parse_line ('\s+', 0, $var))[0]);
1578             }
1579              
1580              
1581             sub test {
1582 0     0 1   my $self = shift;
1583 0           my ($what, $group, $service, $exitval, $period) = @_;
1584 0           my ($r, $l);
1585              
1586 0           undef $self->{"ERROR"};
1587              
1588 0 0         if (!$self->{"CONNECTED"}) {
1589 0           $self->{"ERROR"} = "not connected";
1590 0           return undef;
1591             }
1592              
1593 0 0         if ($what !~ /^monitor|alert|startupalert|upalert$/) {
1594 0           $self->{"ERROR"} = "unknown test";
1595 0           return undef;
1596             }
1597              
1598 0 0         if (!defined $group) {
1599 0           $self->{"ERROR"} = "group not specified";
1600 0           return undef;
1601             }
1602              
1603 0 0         if (!defined $service) {
1604 0           $self->{"ERROR"} = "service not specified";
1605 0           return undef;
1606             }
1607              
1608 0 0 0       if ($what =~ /^alert|startupalert|upalert$/ &&
      0        
1609             ($exitval eq "" || $period eq "")) {
1610 0           $self->{"ERROR"} = "must specify exit value and time period";
1611 0           return undef;
1612             }
1613              
1614 0           ($r, $l) = _do_cmd ($self->{"HANDLE"},
1615             join (" ", "test", $what, $group, $service, $exitval, $period));
1616              
1617 0 0         if (!defined $r) {
    0          
1618 0           $self->{"ERROR"} = $l;
1619 0           return undef;
1620             } elsif ($r !~ /^220/) {
1621 0           $self->{"ERROR"} = $r;
1622 0           return undef;
1623             }
1624              
1625 0           return $r;
1626             }
1627              
1628              
1629             sub test_config {
1630 0     0 1   my $self = shift;
1631 0           my ($r, $l);
1632              
1633 0           undef $self->{"ERROR"};
1634              
1635 0 0         if (!$self->{"CONNECTED"}) {
1636 0           $self->{"ERROR"} = "not connected";
1637 0           return undef;
1638             }
1639              
1640 0           ($r, $l) = _do_cmd ($self->{"HANDLE"}, "test config");
1641              
1642 0 0         if (!defined $r) {
    0          
1643 0           $self->{"ERROR"} = $l;
1644 0           return undef;
1645             } elsif ($r !~ /^220/) {
1646 0           $self->{"ERROR"} = $r;
1647 0           return (0 , $l) ;
1648             }
1649              
1650 0           return (1 , $r);
1651             }
1652              
1653              
1654             sub ack {
1655 0     0 1   my $self = shift;
1656 0           my ($group, $service, $text) = @_;
1657              
1658 0           undef $self->{"ERROR"};
1659              
1660 0 0         if (!$self->{"CONNECTED"}) {
1661 0           $self->{"ERROR"} = "not connected";
1662 0           return undef;
1663             }
1664              
1665 0           $text = _esc_str ($text, 1);
1666              
1667 0           my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "ack $group $service '$text'");
1668              
1669 0 0         if (!defined $r) {
    0          
1670 0           $self->{"ERROR"} = $l;
1671 0           return undef;
1672             } elsif ($r !~ /^220/) {
1673 0           $self->{"ERROR"} = $r;
1674 0           return undef;
1675             }
1676              
1677 0           return $r;
1678             }
1679              
1680              
1681             sub loadstate {
1682 0     0 1   my $self = shift;
1683 0           my (@state) = @_;
1684 0           my ($r, $l);
1685              
1686 0           undef $self->{"ERROR"};
1687              
1688 0 0         if (!$self->{"CONNECTED"}) {
1689 0           $self->{"ERROR"} = "not connected";
1690 0           return undef;
1691             }
1692              
1693 0           ($r, $l) = _do_cmd ($self->{"HANDLE"}, "loadstate @state");
1694              
1695 0 0         if (!defined $r) {
    0          
1696 0           $self->{"ERROR"} = $l;
1697 0           return undef;
1698             } elsif ($r !~ /^220/) {
1699 0           $self->{"ERROR"} = $r;
1700 0           return undef;
1701             }
1702              
1703 0           return $r;
1704             }
1705              
1706              
1707             sub savestate {
1708 0     0 1   my $self = shift;
1709 0           my (@state) = @_;
1710 0           my ($r, $l);
1711              
1712 0           undef $self->{"ERROR"};
1713              
1714 0 0         if (!$self->{"CONNECTED"}) {
1715 0           $self->{"ERROR"} = "not connected";
1716 0           return undef;
1717             }
1718              
1719 0           ($r, $l) = _do_cmd ($self->{"HANDLE"}, "savestate @state");
1720              
1721 0 0         if (!defined $r) {
    0          
1722 0           $self->{"ERROR"} = $l;
1723 0           return undef;
1724             } elsif ($r !~ /^220/) {
1725 0           $self->{"ERROR"} = $r;
1726 0           return undef;
1727             }
1728              
1729 0           return $r;
1730             }
1731              
1732              
1733             sub servertime {
1734 0     0 1   my $self = shift;
1735 0           my ($r, $l, $t);
1736              
1737 0           undef $self->{"ERROR"};
1738              
1739 0 0         if (!$self->{"CONNECTED"}) {
1740 0           $self->{"ERROR"} = "not connected";
1741 0           return undef;
1742             }
1743              
1744 0           ($r, $l) = _do_cmd ($self->{"HANDLE"}, "servertime");
1745              
1746 0 0         if (!defined $r) {
    0          
1747 0           $self->{"ERROR"} = $l;
1748 0           return undef;
1749             } elsif ($r !~ /^220/) {
1750 0           $self->{"ERROR"} = $r;
1751 0           return undef;
1752             }
1753              
1754 0           $l =~ /^(\d+)/;
1755 0           return $1;
1756             }
1757              
1758              
1759             #
1760             # clear timers
1761             #
1762             sub clear {
1763 0     0 0   my $self = shift;
1764 0           my ($r, $l);
1765              
1766 0           undef $self->{"ERROR"};
1767              
1768 0 0         if (!$self->{"CONNECTED"}) {
1769 0           $self->{"ERROR"} = "not connected";
1770 0           return undef;
1771             }
1772              
1773 0           ($r, $l) = _do_cmd ($self->{"HANDLE"}, "clear timers");
1774              
1775 0 0         if (!defined $r) {
    0          
1776 0           $self->{"ERROR"} = $l;
1777 0           return undef;
1778             } elsif ($r !~ /^220/) {
1779 0           $self->{"ERROR"} = $r;
1780 0           return undef;
1781             }
1782              
1783             }
1784              
1785              
1786             # sub crap_cmd {
1787             # my $self = shift;
1788             # my ($r, $l);
1789             #
1790             # undef $self->{ERROR};
1791             #
1792             # if (!$self->{CONNECTED}) {
1793             # $self->{ERROR} = "not connected";
1794             # return undef;
1795             # }
1796             #
1797             # ($r, $l) = _do_cmd ($self->{HANDLE}, "COMMAND");
1798             #
1799             # if (!defined $r) {
1800             # $self->{ERROR} = $l;
1801             # return undef;
1802             # } elsif ($r !~ /^220/) {
1803             # $self->{ERROR} = $r;
1804             # return undef;
1805             # }
1806             #
1807             # }
1808              
1809             sub send_trap {
1810 0     0 1   my $self = shift;
1811 0           my %v = @_;
1812              
1813 0           undef $self->{"ERROR"};
1814              
1815 0 0         if ($v{"retval"} !~ /^\d+$/)
1816             {
1817 0           $self->{"ERROR"} = "invalid value for retval";
1818 0           return undef;
1819             }
1820              
1821 0 0         if (!defined ($v{"opstatus"} = $OPSTAT{$v{"opstatus"}}))
1822             {
1823 0           $self->{"ERROR"} = "Undefined opstatus type";
1824 0           return undef;
1825             }
1826              
1827 0           foreach my $k (keys %v)
1828             {
1829 0           $v{$k} = _esc_str ($v{$k}, 1);
1830             }
1831              
1832 0           my $pkt = "";
1833 0           $pkt .= "pro='" . _esc_str ($self->{"TRAP_PRO_VERSION"}, 1) . "'\n";
1834 0           $pkt .= "usr='" . _esc_str ($self->{"USERNAME"}, 1) . "'\n";
1835 0 0         $pkt .= "pas='" . _esc_str ($self->{"PASSWORD"}, 1) . "'\n"
1836             if ($self->{"USERNAME"} ne "");
1837              
1838 0           $pkt .= "spc='$v{opstatus}'\n" .
1839             "seq='0'\n" .
1840             "typ='trap'\n" .
1841             "grp='$v{group}'\n" .
1842             "svc='$v{service}'\n" .
1843             "sta='$v{retval}'\n" .
1844             "spc='$v{opstatus}'\n" .
1845             "tsp='" . time . "'\n" .
1846             "sum='$v{summary}'\n" .
1847             "dtl='$v{detail}'\n";
1848              
1849 0           my $proto = getprotobyname ("udp");
1850 0 0         if ($proto eq "")
1851             {
1852 0           $self->{"ERROR"} = "could not get proto";
1853 0           return undef;
1854             }
1855              
1856 0 0         if (!socket (TRAP, AF_INET, SOCK_DGRAM, $proto))
1857             {
1858 0           $self->{"ERROR"} = "could not create UDP socket: $!";
1859 0           return undef;
1860             }
1861              
1862 0           my $port = $self->{"PORT"};
1863              
1864 0           my $paddr = sockaddr_in ($port, inet_aton ($self->{"HOST"}));
1865              
1866 0 0         if (!defined (send (TRAP, $pkt, 0, $paddr)))
1867             {
1868 0           $self->{"ERROR"} = "could not send trap to ".$self->{"HOST"}.": $!\n";
1869 0           return undef;
1870             }
1871              
1872 0           close (TRAP);
1873              
1874 0           return 1;
1875             }
1876              
1877              
1878             sub _start_stop {
1879 0     0     my $self = shift;
1880 0           my $cmd = shift;
1881 0           my ($r, $l);
1882              
1883 0           undef $self->{"ERROR"};
1884              
1885 0 0         if (!$self->{"CONNECTED"}) {
1886 0           $self->{"ERROR"} = "not connected";
1887 0           return undef;
1888             }
1889              
1890 0 0 0       if ($cmd ne "start" && $cmd ne "stop") {
1891 0           $self->{"ERROR"} = "undefined command";
1892 0           return undef;
1893             }
1894              
1895 0           ($r, $l) = _do_cmd ($self->{"HANDLE"}, "$cmd");
1896              
1897 0 0         if (!defined $r) {
    0          
1898 0           $self->{"ERROR"} = $l;
1899 0           return undef;
1900             } elsif ($r !~ /^220/) {
1901 0           $self->{"ERROR"} = $r;
1902 0           return undef;
1903             }
1904              
1905 0           return $r;
1906             }
1907              
1908              
1909             sub _list_opstatus {
1910 0     0     my ($self, $cmd) = @_;
1911 0           my (%op, $o, %opstatus);
1912 0           my ($group, $service, $last, $timer, $summary);
1913              
1914 0           undef $self->{"ERROR"};
1915              
1916 0 0         if (!$self->{"CONNECTED"}) {
1917 0           $self->{"ERROR"} = "not connected";
1918 0           return undef;
1919             }
1920              
1921 0           my ($r, @op) = _do_cmd ($self->{"HANDLE"}, "$cmd");
1922              
1923 0 0         if (!defined $r) {
    0          
1924 0           $self->{"ERROR"} = $op[0];
1925 0           return undef;
1926             } elsif ($r !~ /^220/) {
1927 0           $self->{"ERROR"} = $r;
1928 0           return undef;
1929             }
1930              
1931 0           foreach $o (@op) {
1932 0           foreach my $w (quotewords ('\s+', 0, $o)) {
1933 0           my ($var, $val) = split (/=/, $w, 2);
1934 0           $op{$var} = _un_esc_str ($val);
1935             }
1936              
1937 0 0         next if ($op{group} eq "");
1938 0 0         next if ($op{service} eq "");
1939 0           $group = $op{"group"};
1940 0           $service = $op{"service"};
1941 0           foreach my $w (keys %op) {
1942 0           $opstatus{$group}{$service}{$w} = $op{$w};
1943             }
1944             }
1945              
1946 0           return %opstatus;
1947             }
1948              
1949              
1950             sub _sock_write {
1951 0     0     my ($sock, $buf) = @_;
1952 0           my ($nleft, $nwritten);
1953              
1954 0           $nleft = length ($buf);
1955 0           while ($nleft) {
1956 0           $nwritten = syswrite ($sock, $buf, $nleft);
1957 0 0         return undef if (!defined ($nwritten));
1958 0           $nleft -= $nwritten;
1959 0           substr ($buf, 0, $nwritten) = "";
1960             }
1961             }
1962              
1963              
1964             sub _do_cmd {
1965 0     0     my ($fd, $cmd) = @_;
1966 0           my ($l, @out);
1967              
1968 0           @out = ();
1969 0 0         return (undef) if (!defined _sock_write ($fd, "$cmd\n"));
1970              
1971 0           for (;;) {
1972 0           $l = _sock_readline ($fd);
1973 0 0         return (undef) if (!defined $l);
1974 0           chomp ($l);
1975              
1976 0 0         if ($l =~ /^(\d{3}\s)/) {
1977 0           last;
1978             }
1979 0           push (@out, $l);
1980             }
1981              
1982 0           ($l, @out);
1983             }
1984              
1985              
1986             sub _sock_readline {
1987 0     0     my ($sock) = @_;
1988              
1989 0           my $l = <$sock>;
1990 0           return $l;
1991             }
1992              
1993             1;
1994              
1995             #
1996             # not yet implemented
1997             #
1998             #list aliasgroups
1999              
2000              
2001             sub _esc_str {
2002 0     0     my $str = shift;
2003 0           my $inquotes = shift;
2004 0           my $escstr = "";
2005              
2006 0           for (my $i = 0; $i < length ($str); $i++)
2007             {
2008 0           my $c = substr ($str, $i, 1);
2009              
2010 0 0 0       if (ord ($c) < 32 ||
    0 0        
      0        
      0        
2011             ord ($c) > 126 ||
2012             $c eq "\"" ||
2013             $c eq "\'")
2014             {
2015 0           $c = sprintf ("\\%02x", ord($c));
2016             }
2017             elsif ($inquotes && $c eq "\\")
2018             {
2019 0           $c = "\\\\";
2020             }
2021              
2022 0           $escstr .= $c;
2023             }
2024              
2025 0           $escstr;
2026             }
2027              
2028             sub _un_esc_str {
2029 0     0     my $str = shift;
2030              
2031 0           $str =~ s{\\([0-9a-f]{2})}{chr(hex($1))}eg;
  0            
2032              
2033 0           $str;
2034             }
2035              
2036             sub list_aliases {
2037 0     0 0   my $self = shift;
2038 0           my ($r, @d, $d, $group, $service, @allAlias, $aliasBlock, %alias);
2039              
2040 0           undef $self->{ERROR};
2041              
2042 0 0         if (!$self->{CONNECTED}) {
2043 0           $self->{ERROR} = "not connected";
2044 0           return undef;
2045             }
2046              
2047 0           ($r, @d) = _do_cmd ($self->{HANDLE}, "list aliases");
2048              
2049 0 0         if (!defined $r) {
    0          
2050 0           $self->{ERROR} = "error (@d)";
2051 0           return undef;
2052             } elsif ($r !~ /^220/) {
2053 0           $self->{ERROR} = $r;
2054 0           return undef;
2055             }
2056              
2057 0 0         return $r if (!defined $r);
2058              
2059             # the block separator is \n\n
2060 0           @allAlias = split (/\n\n/ ,join ("\n", @d));
2061 0           foreach $aliasBlock (@allAlias) {
2062 0           my(@allServices, $headerAlias, @headerAlias, $nameLine, $name, $description);
2063            
2064             # extract the service block
2065 0           @allServices = split ( /\nservice\s*/, $aliasBlock);
2066             # The first element is not a service block, it is the alias header
2067             # alias FOO
2068             # FOO is a good service
2069             # FOO bla bla
2070 0           $headerAlias = shift (@allServices);
2071             # Split the block to get the name and the description
2072 0           @headerAlias = split (/\n/, $headerAlias);
2073 0           $nameLine = shift(@headerAlias);
2074 0           $nameLine =~ /\Aalias\s+(\S+)/;
2075 0           $name = $1;
2076            
2077 0           $headerAlias = join("\n", @headerAlias);
2078 0 0         $alias{$name}{'declaration'} = ($headerAlias) ? $headerAlias : '?';
2079            
2080 0           foreach $service (@allServices) {
2081 0           my($serviceName, @allWatch, $watch);
2082 0           @allWatch = split ("\n", $service);
2083 0           $serviceName = shift(@allWatch);
2084 0           foreach $watch (@allWatch) {
2085 0           my($groupWatched, $serviceWatched, @items, $url);
2086 0 0         if($watch =~ /\Awatch\s+(\S+)\s+service\s+(\S+)\s+items\s*(.*)\Z/){
    0          
2087 0           $groupWatched = $1;
2088 0           $serviceWatched = $2;
2089 0           @items = split(/\s+/, $3);
2090 0           $alias{$name}{'service'}{$serviceName}{'watch'}{$groupWatched}{'service'}{$serviceWatched}{'items'} = [ @items ];
2091            
2092             }elsif($watch =~ /\Aurl\s+(.*)\Z/){
2093 0           $url = $1;
2094 0           $alias{$name}{'service'}{$serviceName}{'url'} = $url;
2095             }
2096             }
2097             }
2098            
2099             }
2100 0           return %alias;
2101             }