File Coverage

blib/lib/System/InitD/Runner.pm
Criterion Covered Total %
statement 36 141 25.5
branch 0 52 0.0
condition 0 8 0.0
subroutine 12 27 44.4
pod 3 15 20.0
total 51 243 20.9


line stmt bran cond sub pod time code
1             package System::InitD::Runner;
2              
3             =head NAME
4              
5             System::InitD::Runner
6              
7             =head1 DESCRIPTION
8              
9             Simple module to process common init.d tasks.
10             init.d bash scripts replacement
11              
12             =head1 AUTHOR
13              
14             Dmitriy @justnoxx Shamatrin
15              
16             =head1 USAGE
17              
18             =cut
19              
20 1     1   5 use strict;
  1         1  
  1         23  
21 1     1   5 use warnings;
  1         1  
  1         22  
22 1     1   4 no warnings qw/once/;
  1         1  
  1         32  
23              
24 1     1   4 use Carp;
  1         1  
  1         68  
25 1     1   677 use System::Process;
  1         11412  
  1         10  
26 1     1   42 use POSIX;
  1         2  
  1         7  
27 1     1   3409 use Time::HiRes;
  1         1949  
  1         5  
28              
29 1     1   652 use System::InitD::Const;
  1         4  
  1         59  
30 1     1   513 use System::InitD::Base;
  1         4  
  1         28  
31 1     1   7 use System::InitD::Const;
  1         1  
  1         943  
32              
33             =over
34              
35             =item B
36              
37             new(%)
38              
39             Constructor, params:
40              
41             B
42              
43             A start command
44              
45             B
46              
47             Usage line, called by script usage
48              
49             B
50              
51             Now unused, reserved for output format
52              
53             B
54              
55             Timeout between stop and start in restart
56              
57             B
58              
59             Path to pid file, which used for monitoring
60              
61             B
62              
63             B daemon process name. Need for preventing wrong kill.
64              
65             B
66              
67             Signal, which used for daemon killing.
68              
69             =back
70              
71             =cut
72              
73              
74             sub new {
75 0     0 1   my ($class, %params) = @_;
76 0           my $self = {};
77              
78 0 0         if (!$params{start}) {
79 0           croak "Start param is required";
80             }
81              
82 0 0         if (!$params{usage}) {
83 0           croak 'Usage must be specified';
84             }
85              
86 0 0         if ($params{daemon_name}) {
87 0           $self->{daemon_name} = $params{daemon_name};
88             }
89              
90             else {
91 0           $self->{_text}->{usage} = $params{usage};
92             }
93              
94             # Command is array from now, for system
95 0           @{$self->{_commands}->{start}} = split /\s+/, $params{start};
  0            
96              
97 0 0         if ($params{restart_timeout}) {
98 0           $self->{_args}->{restart_timeout} = $params{restart_timeout};
99             }
100              
101 0 0         if ($params{pid_file}) {
102 0           $self->{pid} = System::Process::pidinfo(
103             file => $params{pid_file}
104             );
105             }
106              
107 0 0         if ($params{kill_signal}) {
108 0           $self->{_args}->{kill_signal} = $params{kill_signal};
109             }
110              
111 0 0         if ($params{process_name}) {
112 0           $self->{_args}->{process_name} = $params{process_name};
113             }
114              
115             # user and group params, added for right validation
116 0 0         if ($params{user}) {
117 0           $self->{_args}->{user} = $params{user};
118             }
119 0 0         if ($params{group}) {
120 0           $self->{_args}->{group} = $params{group};
121             }
122              
123 0           bless $self, $class;
124 0           return $self;
125             }
126              
127              
128             =over
129              
130             =item B
131              
132             Runner itself, service sub
133              
134             =back
135              
136             =cut
137              
138             sub run {
139 0     0 1   my $self = shift;
140 0 0         unless ($ARGV[0]) {
141 0           $self->usage();
142 0           return 1;
143             }
144              
145 0 0         if ($self->can($ARGV[0])) {
146 0           my $sub = $ARGV[0];
147 0           $self->$sub();
148             }
149             else {
150 0           $self->usage();
151             }
152 0           return 1;
153             }
154              
155              
156             sub start {
157 0     0 0   my $self = shift;
158              
159 0           $self->before_start();
160             # TODO: Add command check
161 0           my @command = @{$self->{_commands}->{start}};
  0            
162 0 0         if ($self->is_alive()) {
163 0           print DAEMON_ALREADY_RUNNING;
164 0           return;
165             }
166 0           system(@command);
167 0           $self->after_start();
168 0           return 1;
169             }
170              
171              
172             sub stop {
173 0     0 0   my $self = shift;
174              
175 0 0         $self->confirm_permissions() or croak "Incorrect permissions. Can't kill";
176              
177 0           $self->before_stop();
178 0 0         if ($self->{pid}) {
179 0   0       my $signal = $self->{kill_signal} // POSIX::SIGTERM;
180 0           $self->{pid}->kill($signal);
181             }
182              
183 0           $self->after_stop();
184 0           return 1;
185             }
186              
187              
188             sub restart {
189 0     0 0   my $self = shift;
190              
191 0           $self->stop();
192              
193 0           while ($self->is_alive()) {
194 0           Time::HiRes::usleep(1000);
195             }
196              
197 0           $self->start();
198 0           return 1;
199             }
200              
201              
202             sub status {
203 0     0 0   my $self = shift;
204              
205 0 0         unless ($self->{pid}) {
206 0           print DAEMON_IS_NOT_RUNNING;
207 0           exit 0;
208             }
209              
210 0 0         if ($self->is_alive()) {
211 0           print DAEMON_ALREADY_RUNNING;
212             }
213              
214 0           exit 0;
215             }
216              
217              
218             sub info {
219 0     0 0   my $self = shift;
220              
221 0 0         unless ($self->{pid}) {
222 0           print DAEMON_IS_NOT_RUNNING;
223 0           exit 0;
224             }
225              
226 0 0         if ($self->is_alive()) {
227 0           my $p = $self->{pid};
228 0           printf "Daemon is running.\n\tPID: %s\n\tCommand: %s\n\tUser: %s\n",
229             $p->pid(), $p->command(), $p->user();
230             }
231             else {
232 0           print DAEMON_IS_NOT_RUNNING;
233             }
234              
235 0           exit 0;
236              
237             }
238             sub usage {
239 0     0 0   my $self = shift;
240              
241 0           print $self->{_text}->{usage}, "\n";
242 0           return 1;
243             }
244              
245              
246             sub is_alive {
247 0     0 0   my $self = shift;
248 0 0         return 0 unless $self->{pid};
249              
250 0 0 0       return 1 if $self->{_args}->{process_name} eq $self->{pid}->command() && $self->{pid}->cankill();
251              
252 0           return 0;
253             }
254              
255              
256             =over
257              
258             =item B
259              
260             load($,\&)
261              
262             Loads additional actions to init script, for example, add `script hello` possible via:
263              
264             $runner->load('hello', sub {print 'Hello world'})
265              
266             =back
267              
268             =cut
269              
270             sub load {
271 0     0 1   my ($self, $subname, $subref) = @_;
272              
273 0 0 0       if (!$subname || !$subref) {
274 0           croak 'Missing params';
275             }
276              
277 0 0         croak 'Subref must be a CODE ref' if (ref $subref ne 'CODE');
278              
279 1     1   5 no strict 'refs';
  1         2  
  1         51  
280 0           *{__PACKAGE__ . "\::$subname"} = $subref;
  0            
281 1     1   4 use strict 'refs';
  1         1  
  1         298  
282              
283 0           return 1;
284             }
285              
286              
287             sub confirm_permissions {
288 0     0 0   my ($self) = @_;
289              
290 0 0         if (!exists $self->{pid}) {
291 0           carp 'Usage of System::InitD without pidfile is deprecated ' .
292             'and will be forbidden in the future releases';
293 0           return 1;
294             }
295              
296 0 0         unless ($self->{_args}->{user}) {
297 0           carp 'Usage of System::InitD without specified user is extremely insecure ' .
298             'and will be forbidden in the future releases';
299 0           return 1;
300             }
301              
302             # if no System::Process object, next check useless
303 0 0         unless ($self->{pid}) {
304 0           return 1;
305             }
306              
307 0 0         if ($self->{_args}->{user} ne $self->{pid}->user()) {
308 0           carp "Expected: $self->{_args}->{user}, but got: " . $self->{pid}->user()
309             . " looks like very strange. Execution was aborted.";
310 0           return 0;
311             }
312              
313 0           return 1;
314             }
315              
316 0     0 0   sub before_start {1;}
317 0     0 0   sub after_start {1;}
318              
319 0     0 0   sub before_stop {1;}
320 0     0 0   sub after_stop {1;}
321              
322              
323             1;
324              
325             __END__