File Coverage

blib/lib/Proc/Daemontools.pm
Criterion Covered Total %
statement 15 110 13.6
branch 0 54 0.0
condition 0 6 0.0
subroutine 5 14 35.7
pod 6 7 85.7
total 26 191 13.6


line stmt bran cond sub pod time code
1             #
2             # Daemontools.pm - Perl interface for the functionalities of Daemontools
3             # Author: Bruno Negrao G. Zica - bnegrao@engepel.com.br
4             #
5              
6             package Proc::Daemontools;
7 1     1   13312 use 5.008;
  1         6  
  1         2375  
8 1     1   423 use strict;
  1         7  
  1         66  
9 1     1   44 use warnings;
  1         2  
  1         49  
10 1     1   6 use Carp;
  1         2  
  1         280  
11 1     1   7 use vars qw($VERSION);
  1         7  
  1         2225  
12              
13             $VERSION = "1.06";
14              
15             #########################################################
16             # ENVIRONMENTAL CONFIGURATION VARIABLES (default values)
17             #########################################################
18             #
19             # These values are the default values for these variables.
20             # All of them can be overwritten by arguments passed to the new() method.
21             #
22             # Path to directory containing the daemontools executables
23             # (supervise, svc, svok, svstat, etc):
24             my $DAEMONTOOLS_DIR = "/usr/local/bin";
25              
26             # Path to directory monitored by supervise
27             my $SERVICE_DIR = "/service";
28              
29             # The default daemon
30             my $DAEMON = undef;
31              
32             # Required executables - without them we canīt work
33             my @REQ_EXECS = qw ( svc svok svstat );
34              
35             sub new {
36             # the code bellow add support for object cloning.
37             # See Perl Cookbook, 13.6. Cloning Objects
38 0     0 1   my $proto = shift;
39 0   0       my $class = ref($proto) || $proto;
40 0   0       my $parent = ref($proto) && $proto;
41 0           my %options = @_;
42 0           my $self = { };
43 0           bless($self, $class);
44             # Set the atribute values:
45 0 0         if ($parent) {
46             # Inherit these values from the father
47 0           $self->{"DAEMONTOOLS_DIR"} = $parent->{"DAEMONTOOLS_DIR"};
48 0           $self->{"SERVICE_DIR"} = $parent->{"SERVICE_DIR"};
49 0           $self->{"DAEMON"} = $parent->{"DAEMON"};
50             } else {
51             # Set the default values
52 0           $self->{"DAEMONTOOLS_DIR"} = $DAEMONTOOLS_DIR;
53 0           $self->{"SERVICE_DIR"} = $SERVICE_DIR;
54 0           $self->{"DAEMON"} = $DAEMON;
55             }
56             # now, override these values with those received by
57             # the user: (ignoring misspelled options passed, if any)
58 0           my $key;
59 0           foreach $key (keys %options) {
60 0 0         if ( exists $self->{$key} ) {
61             # the regex bellow remove any trailing / from the end of
62             # the directory name
63 0           $options{$key} =~ s|/$||;
64 0           $self->{$key} = $options{$key};
65             }
66             }
67             # the function bellow tests if every system tool needed can be found
68 0           $self->_checkEnv(); # this function will croak if something went wrong
69            
70             # declare the complete path to the required executables
71 0           my $dir = $self->{"DAEMONTOOLS_DIR"};
72 0           foreach (@REQ_EXECS) {
73 0           $self->{$_} = "$dir/$_";
74             }
75 0           return $self;
76             }
77              
78             # _checkEnv() Checks for the presence of the required executables
79             sub _checkEnv { # returns: void
80 0     0     my $self = shift;
81 0           my $dir = $self->{"DAEMONTOOLS_DIR"};
82 0           my @execs = @REQ_EXECS;
83 0           foreach (@execs) {
84 0 0         unless ( -e "$dir/$_" ) {
85 0           croak "ERROR: the file $_ cannot be found on directory $dir. " .
86             "Verify if you set the DAEMONTOOLS_DIR parameter correctly";
87             }
88 0 0         unless ( -x "$dir/$_" ) {
89 0           croak "ERROR: the file $_ is not executable by this user.";
90             }
91             }
92            
93 0           my $dir2 = $self->{"SERVICE_DIR"};
94 0 0         unless ( -e $dir2 ) {
95 0           croak "ERROR: the directory $dir2 doesnīt exist. ".
96             "Verify if you set the SERVICE_DIR parameter correctly.";
97             }
98 0 0         unless ( -x $dir2 ) {
99 0           croak "ERROR: the directory $dir2 is not executable by this user.";
100             }
101            
102 0 0         if ( $self->{"DAEMON"} ) {
103 0           my $daemon = "$dir2/" . $self->{"DAEMON"};
104 0 0         unless ( -e $daemon ) {
105 0           croak "ERROR: canīt find the daemon $daemon. Verify if you set ".
106             "the DAEMON parameter correctly.";
107             }
108 0 0         unless (-x $daemon ) {
109 0           croak "ERROR: the directory $daemon is not executable by this user.";
110             }
111             }
112             }
113              
114             # Acessor method daemon(): to get/set the DAEMON atribute
115             sub daemon() { # returns: string
116 0     0 1   my $self = shift;
117 0 0         if (@_) { $self->{"DAEMON"} = shift; }
  0            
118 0           return $self->{"DAEMON"};
119             }
120            
121             sub up () { # returns: boolean
122 0     0 1   my $self = shift;
123 0           return $self->doSvc(@_); #returns the boolean returned by doSvc()
124             }
125              
126             sub down () { # returns: boolean
127 0     0 1   my $self = shift;
128 0           return $self->doSvc(@_); #returns the boolean returned by doSvc()
129             }
130              
131             # doSvc() uses the svc executable. It only returns true when the svc command really
132             # performed what it was suposed to do.
133             # This method cannot be run directly, instead it have to be called from methods with
134             # special names, as up() and down()
135             # Ex:
136             # To start qmail-send(within the up() method): $self->doSvc("qmail-send");
137             # To start the default daemon(within the up() method): $self->doSvc();
138             # To stop qmail-smtpd(within the down() method): $self->doSvc("qmail-smtpd");
139             sub doSvc() { # returns: boolean
140 0     0 0   my $self = shift;
141 0 0         my $daemon = $_[0] ? $_[0] : $self->daemon();
142 0           (caller(1))[3] =~ /::(\w+)$/;
143 0           my $caller = $1; # this variable will define what option svc will receive
144 0           my $daemon_dir = $self->{"SERVICE_DIR"} . "/" . $daemon;
145 0 0         croak "ERROR: directory $daemon_dir doesnīt exist or is not " .
146             "accessible. " unless ( -x $daemon_dir );
147 0           my $svc = $self->{"svc"};
148 0           my $svok = $self->{"svok"};
149 0           my $opt; # option to svc (-u, -d, -t, etc)
150             # defining $opt
151 0 0         if ( $caller =~ /up/ ) {
    0          
152 0           $opt = "-u";
153             } elsif ( $caller =~ /down/ ) {
154 0           $opt = "-d";
155             }
156             # svok returns 0 for success and non-zero for failure. Also, it only
157             # issues an output when there was an error
158 0 0         open (FH, "$svok $daemon_dir 2>&1|") or
159             croak "ERROR: cannot run svok: $!";
160 0           my $output = ;
161 0           close FH;
162 0           my $ERROR;
163 0 0         if ($? != 0) { # there was an error
164 0           $ERROR = "ERROR: svok said that supervise is not running successfully on " .
165             " directory $daemon_dir.";
166 0 0         if ($output) { $ERROR .= " svok said: "; }
  0            
167 0           croak $ERROR;
168             }
169             # svc always return 0 even if it encountered an error. Also, it only outputs
170             # anything when something bad occured, hence we need to check its stderr:
171 0           $output = `$svc $opt $daemon_dir 2>&1`;
172 0 0         croak "ERROR: $svc failed. It said: $output" if $output;
173              
174             # Now we gonna check if doSvc() actually did what it tried to do.
175 0 0         $self->_isDaemon($daemon, $caller) ?
176             return 1 :
177             return 0;
178             }
179              
180             # _isDaemon() - An interface to svstat
181             # Synopsis: $self->("daemon" [,state]);
182             # Tells if the daemon is in a determined state. States are: up, down.
183             # If it doesnīt receive an state string, it will return a string containing the output
184             # of svstat about the required daemon.
185             # To know if qmail-send is stopped:
186             # my $boolean = $self->_isDaemon("qmail-send", "down");
187             # To know if qmail-smtpd is started:
188             # my $boolean = $self->_isDaemon("qmail-smtpd", "up");
189             sub _isDaemon (@) { # returns: boolean or string.
190 0     0     my $self = shift;
191 0           my $daemon = shift;
192 0 0         my $state = @_ ? shift : "Print-Output";
193 0           my $daemon_dir = $self->{"SERVICE_DIR"} . "/" . $daemon;
194 0 0         croak "ERROR: directory $daemon_dir doesnīt exist or is not " .
195             "accessible. " unless ( -x $daemon_dir );
196 0           my $svstat = $self->{"svstat"}; # the svstat executable
197 0           my $boolean = undef; # what will be returned by this method
198             # svstat always return 0 and always outputs to stdout even when thereīs an error
199 0 0         open (FH, "$svstat $daemon_dir|" ) or
200             croak "ERROR: canīt execute the command \'$svstat $daemon_dir\': $!";
201 0           my $output = ;
202 0           close FH;
203 0 0         if ($state =~ /Print-Output/ ) {
    0          
    0          
204 0           $boolean = $output; # output of svstat will be printed
205             } elsif ($state =~ /up/) {
206 0           $boolean = $output =~ /^$daemon_dir: up/;
207             } elsif ($state =~ /down/) {
208 0           $boolean = $output =~ /^$daemon_dir: down/;
209             }
210 0           return $boolean;
211             }
212              
213             # Ex: if ( $self->is_up("qmail-smtpd") ) { print "SMTPD IS UP";}
214             # or: if ( $self->is_up() ) { print "$self->daemon() IS UP";}
215             sub is_up () { # returns: boolean
216 0     0 1   my $self = shift;
217 0 0         my $daemon = $_[0] ? $_[0] : $self->daemon();
218 0           return $self->_isDaemon($daemon, "up");
219             }
220              
221             sub status () { # returns: string
222 0     0 1   my $self = shift;
223 0 0         my $daemon = $_[0] ? $_[0] : $self->daemon();
224 0           return $self->_isDaemon($daemon);
225             }
226              
227             1;
228             __END__