LP#1711194 osrf_config --diagnostic reports max-children
[OpenSRF.git] / bin / opensrf-perl.pl.in
1 #!/usr/bin/perl
2 # ---------------------------------------------------------------
3 # Copyright (C) 2008-2013 Georgia Public Library Service
4 # Copyright (C) 2013 Equinox Software, Inc
5 # Bill Erickson <berick@esilibrary.com>
6 #
7 # This program is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU General Public License
9 # as published by the Free Software Foundation; either version 2
10 # of the License, or (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 # ---------------------------------------------------------------
17 use strict; use warnings;
18 use Getopt::Long;
19 use Net::Domain qw/hostfqdn/;
20 use POSIX qw/setsid :sys_wait_h/;
21 use OpenSRF::Utils::Logger q/$logger/;
22 use OpenSRF::System;
23 use OpenSRF::Transport::PeerHandle;
24 use OpenSRF::Utils::SettingsClient;
25 use OpenSRF::Transport::Listener;
26 use OpenSRF::Utils;
27 use OpenSRF::Utils::Config;
28
29 my $opt_service = undef;
30 my $opt_config = "@CONF_DIR@/opensrf_core.xml";
31 my $opt_pid_dir = "@PID_DIR@/run/opensrf";
32 my $opt_no_daemon = 0;
33 my $opt_settings_pause = 0;
34 my $opt_localhost = 0;
35 my $opt_help = 0;
36 my $opt_shutdown_graceful = 0;
37 my $opt_shutdown_fast = 0;
38 my $opt_shutdown_immediate = 0;
39 my $opt_shutdown_graceful_all = 0;
40 my $opt_shutdown_fast_all = 0;
41 my $opt_shutdown_immediate_all = 0;
42 my $opt_kill_with_fire = 0;
43 my $opt_signal = ''; # signal name
44 my $opt_signal_all = 0;
45 my $opt_signal_timeout = 30;
46 my $opt_start = 0;
47 my $opt_stop = 0;
48 my $opt_restart = 0;
49 my $opt_start_all = 0;
50 my $opt_stop_all = 0;
51 my $opt_restart_all = 0;
52 my $opt_start_services = 0;
53 my $opt_stop_services = 0;
54 my $opt_restart_services = 0;
55 my $opt_force_clean_process = 0;
56 my $opt_router_de_register = 0;
57 my $opt_router_de_register_all = 0;
58 my $opt_router_re_register = 0;
59 my $opt_router_re_register_all = 0;
60 my $opt_reload = 0;
61 my $opt_reload_all = 0;
62 my $opt_quiet = 0;
63 my $opt_diagnostic = 0;
64 my $opt_ignore_orphans = 0;
65 my $sclient;
66 my @perl_services;
67 my @nonperl_services;
68 my %max_children_map;
69 my $hostname = $ENV{OSRF_HOSTNAME} || hostfqdn();
70
71 GetOptions(
72     'service=s' => \$opt_service,
73     'config=s' => \$opt_config,
74     'pid-dir=s' => \$opt_pid_dir,
75     'no-daemon' => \$opt_no_daemon,
76     'settings-startup-pause=i' => \$opt_settings_pause,
77     'localhost' => \$opt_localhost,
78     'help' => \$opt_help,
79     'quiet' => \$opt_quiet,
80     'graceful-shutdown' => \$opt_shutdown_graceful,
81     'fast-shutdown' => \$opt_shutdown_fast,
82     'immediate-shutdown' => \$opt_shutdown_immediate,
83     'graceful-shutdown-all' => \$opt_shutdown_graceful_all,
84     'fast-shutdown-all' => \$opt_shutdown_fast_all,
85     'immediate-shutdown-all' => \$opt_shutdown_immediate_all,
86     'kill-with-fire' => \$opt_kill_with_fire,
87     'force-clean-process' => \$opt_force_clean_process,
88     'signal-timeout' => \$opt_signal_timeout,
89     'signal=s' => \$opt_signal,
90     'signal-all' => \$opt_signal_all,
91     'start' => \$opt_start,
92     'stop' => \$opt_stop,
93     'start-all' => \$opt_start_all,
94     'stop-all' => \$opt_stop_all,
95     'restart' => \$opt_restart,
96     'restart-all' => \$opt_restart_all,
97     'start-services' => \$opt_start_services,
98     'stop-services' => \$opt_stop_services,
99     'restart-services' => \$opt_restart_services,
100     'router-de-register' => \$opt_router_de_register,
101     'router-de-register-all' => \$opt_router_de_register_all,
102     'router-re-register' => \$opt_router_re_register,
103     'router-re-register-all' => \$opt_router_re_register_all,
104     'reload' => \$opt_reload,
105     'reload-all' => \$opt_reload_all,
106     'diagnostic' => \$opt_diagnostic,
107     'ignore-orphans' => \$opt_ignore_orphans
108 );
109
110 if ($opt_localhost) {
111     $hostname = 'localhost';
112     $ENV{OSRF_HOSTNAME} = $hostname;
113 }
114
115 my $C_COMMAND = "opensrf-c -c $opt_config -x opensrf -p $opt_pid_dir -h $hostname";
116 my $PY_COMMAND = "opensrf.py -f $opt_config -p $opt_pid_dir ". ($opt_localhost ? '-l' : '');
117
118 sub verify_services {
119     my $service = shift;
120     return 1 if $service and $service eq 'router';
121     my @services = (@perl_services, map {$_->{service}} @nonperl_services);
122     if (@services) {
123         return 1 unless $service;
124         return 1 if grep { $_ eq $service } @services;
125         msg("$service is not configured to run on $hostname");
126     } else {
127         msg("No services are configured to run on $hostname");
128     }
129     msg("Perhaps you meant to use --localhost?") unless $opt_localhost;
130     exit;
131 }
132
133 sub do_signal_send {
134     my $service = shift;
135     my $signal = shift;
136
137     my @pids = get_service_pids_from_file($service);
138
139     if (!@pids) {
140         # no PID files exist.  see if the service is running anyway
141
142         @pids = get_service_pids_from_ps($service);
143         if (!@pids) {
144             msg("cannot signal $service : no pid file or running process");
145             return 0;
146         }
147     }
148
149     for my $pid (@pids) {
150         if (kill($signal, $pid) == 0) { # no process was signaled.  
151             msg("cannot signal $service: process $pid is not running");
152             my $pidfile = get_pid_file($service);
153             unlink $pidfile if $pidfile;
154             next;
155         }
156
157         msg("sending $signal signal to pid=$pid $service");
158     }
159
160     return 1;
161 }
162
163 # returns 2 if a process should have gone away but did not
164 # in the case of multiple PIDs (e.g. router), return the 
165 # status of any failures, but not the successes.
166 sub do_signal_wait {
167     my $service = shift;
168     my @pids = get_service_pids_from_file($service);
169
170     my $stat = 1;
171     for my $pid (@pids) {
172
173         # to determine whether a process has died, we have to send
174         # a no-op signal to the PID and check the success of that signal
175         my $sig_count;
176         for my $i (1..$opt_signal_timeout) {
177             $sig_count = kill(0, $pid);
178             last unless $sig_count;
179             sleep(1);
180         }
181
182         if ($sig_count) {
183             msg("timed out waiting on $service pid=$pid to die");
184             $stat = 2;
185             next;
186         }
187
188         # cleanup successful. remove the PID file
189         my $pidfile = get_pid_file($service);
190         unlink $pidfile if $pidfile;
191     }
192
193     return $stat;
194 }
195
196 sub get_pid_file {
197     my $service = shift;
198     return "$opt_pid_dir/$service.pid";
199 }
200
201 # services usually only have 1 pid, but the router will have at least 2
202 sub get_service_pids_from_file {
203     my $service = shift;
204     my $pid_file = get_pid_file($service);
205     return () unless -e $pid_file;
206     my @pids = `cat $pid_file`;
207     s/^\s*|\n//g for @pids;
208     return @pids;
209 }
210
211 sub get_service_pids_from_ps {
212     my $service = shift;
213
214     my $ps = ($service eq 'router') ?
215         "ps x | grep 'OpenSRF Router'" :
216         "ps x | grep 'OpenSRF Listener \\[$service\\]'";
217
218     $ps .= " | grep -v grep |  sed 's/^\\s*//' | cut -d' ' -f1";
219     my @pids = `$ps`;
220     s/^\s*|\n//g for @pids;
221
222     return @pids;
223 }
224
225
226 sub do_diagnostic {
227     my $alive = do_init(1);
228
229     my @services = get_service_list_from_files(1);
230     my @conf_services;
231     if ($alive) {
232         @conf_services = (@perl_services, 
233             map {$_->{service}} @nonperl_services);
234         push(@services, @conf_services);
235     }
236     
237     my %services;
238     my $len = 0;
239     for my $svc (@services) {
240         $len = length($svc) if length($svc) > $len;
241         $services{$svc} = 1;
242     }
243
244     for my $svc (sort keys %services) {
245         my @pf_pids = get_service_pids_from_file($svc);
246         my @ps_pids = get_service_pids_from_ps($svc); 
247         my $svc_str = sprintf("%-${len}s ", $svc);
248         my %seen;
249
250         unless(@ps_pids or @pf_pids) {
251             msg("$svc_str is not running");
252             next;
253         }
254
255         for my $pid (@ps_pids) {
256             $seen{$pid} = 1;
257
258             my $str = "$svc_str [$pid] ";
259             my $times = `ps -o etime=,cputime= $pid`;
260             $times =~ s/^\s+|\s+$//g;
261             my @times = split(/ /, $times);
262             $str .= sprintf("uptime=%-11s cputime=%-11s ", $times[0], $times[1]);
263
264             if ($svc eq 'router') {
265                 msg($str);
266             } else {
267                 my @drones = `pgrep -f "Drone \\[$svc\\]"`;
268                 my $dcount = scalar(@drones);
269                 my $dmax = $max_children_map{$svc};
270                 $str .= "#drones=$dcount/$dmax ";
271                 $str .= sprintf('%3d%%', (int(($dcount / $dmax) * 100)));
272                 msg($str);
273                 msg("\tERR $svc has no running drones.") unless @drones;
274             }
275
276             msg("\tERR $svc [$pid] NOT configured for this host.")
277                 unless grep {$_ eq $svc} @conf_services 
278                 or $svc eq 'router';
279
280             msg("\tERR $svc [$pid] NOT found in PID file.")
281                 unless grep {$_ eq $pid} @pf_pids;
282         }
283
284         for my $pid (@pf_pids) {
285             next if $seen{$pid};
286             msg("\tERR $svc Has PID file entry [$pid], ".
287                 "which matches no running $svc processes");
288         }
289     }
290 }
291
292
293
294 sub do_start_router {
295
296     my $pidfile = get_pid_file('router');
297     `opensrf_router $opt_config routers $pidfile`;
298
299     sleep 2; # give the router time to fork (probably not need now but w/e)
300 }
301
302 # stop a specific service
303 sub do_stop {
304     my ($service, @signals) = @_;
305     @signals = qw/TERM INT KILL/ unless @signals;
306     for my $sig (@signals) {
307         last unless do_signal($service, $sig) == 2;
308     }
309     return 1;
310 }
311
312 sub do_init {
313     my $fail_ok = shift;
314
315     OpenSRF::System->bootstrap_client(config_file => $opt_config);
316
317     if (!OpenSRF::Transport::PeerHandle->retrieve) {
318         return 0 if $fail_ok;
319         die "Unable to bootstrap client for requests\n";
320     }
321
322     load_settings(); # load the settings config if we can
323
324     my $sclient = OpenSRF::Utils::SettingsClient->new;
325     my $apps = $sclient->config_value("activeapps", "appname");
326
327     # disconnect the top-level network handle
328     OpenSRF::Transport::PeerHandle->retrieve->disconnect;
329
330     if($apps) {
331         $apps = [$apps] unless ref $apps;
332         for my $app (@$apps) {
333             if (!$sclient->config_value('apps', $app)) {
334                 msg("Service '$app' is listed for this host, ".
335                     "but there is no configuration for it in $opt_config");
336                 next;
337             }
338             my $lang = $sclient->config_value('apps', $app, 'language') || '';
339
340             $max_children_map{$app} = $sclient->config_value(
341                 'apps', $app, 'unix_config', 'max_children');
342
343             if ($lang =~ /perl/i) {
344                 push(@perl_services, $app);
345             } else {
346                 push(@nonperl_services, {service => $app, lang => $lang});
347             }
348         }
349     }
350     return 1;
351 }
352
353 # start a specific service
354 sub do_start {
355     my $service = shift;
356
357     my @pf_pids = get_service_pids_from_file($service);
358     my @ps_pids = get_service_pids_from_ps($service); 
359
360     if (@pf_pids) { # had pidfile
361
362         if (@ps_pids) {
363             msg("service $service already running : @ps_pids");
364             return;
365
366         } else { # stale pidfile
367
368             my $pidfile = get_pid_file($service);
369             msg("removing stale pid file $pidfile");
370             unlink $pidfile;
371         }
372
373     } elsif (@ps_pids and not $opt_ignore_orphans) { # orphan process
374
375         if ($opt_force_clean_process) {
376             msg("service $service pid=@ps_pids is running with no pidfile");
377             do_signal($service, 'KILL');
378         } else {
379             msg("service $service pid=@ps_pids is running with no pidfile! ".
380                 "use --force-clean-process to automatically kill orphan processes");
381             return;
382         }
383     }
384
385     return do_start_router() if $service eq 'router';
386
387     load_settings() if $service eq 'opensrf.settings';
388
389     if(grep { $_ eq $service } @perl_services) {
390         return unless do_daemon($service);
391         OpenSRF::System->run_service($service, $opt_pid_dir);
392
393     } else {
394         # note: we don't daemonize non-perl services, but instead
395         # assume the controller for other languages manages that.
396         my ($svc) = grep { $_->{service} eq $service } @nonperl_services;
397         if ($svc) {
398             if ($svc->{lang} =~ /c/i) {
399                 system("$C_COMMAND -a start -s $service");
400                 return;
401             } elsif ($svc->{lang} =~ /python/i) {
402                 system("$PY_COMMAND -a start -s $service");
403                 return;
404             }
405         }
406     }
407
408     # should not get here
409     return 0;
410 }
411
412
413 sub do_start_all {
414     msg("starting router and services for $hostname");
415     do_start('router');
416     return do_start_services();
417 }
418
419 sub do_start_services {
420     msg("starting services for $hostname");
421
422     if(grep {$_ eq 'opensrf.settings'} @perl_services) {
423         do_start('opensrf.settings');
424         # in batch mode, give opensrf.settings plenty of time to start 
425         # before any non-Perl services try to connect
426         sleep $opt_settings_pause if $opt_settings_pause;
427     }
428
429     # start Perl services
430     for my $service (@perl_services) {
431         do_start($service) unless $service eq 'opensrf.settings';
432     }
433
434     # start each non-perl service individually instead of using the native
435     # start-all command.  this allows us to test for existing pid files 
436     # and/or running processes on each service before starting.
437     # it also means each service has to connect-fetch_setting-disconnect
438     # from jabber, which makes startup slightly slower than native start-all
439     do_start($_->{service}) for @nonperl_services;
440
441     return 1;
442 }
443
444 # signal a single service
445 sub do_signal {
446     my $service = shift;
447     my $signal = shift;
448     return do_signal_all($signal, $service);
449 }
450
451 # returns the list of running services based on presence of PID files.
452 # the 'router' service is not included by deault, since it's 
453 # usually treated special.
454 sub get_service_list_from_files {
455     my $include_router = shift;
456     my @services = `ls $opt_pid_dir/*.pid 2> /dev/null`;
457     s/^\s*|\n//g for @services;
458     s|.*/(.*)\.pid$|$1| for @services;
459     return @services if $include_router;
460     return grep { $_ ne 'router' } @services;
461
462
463 sub do_signal_all {
464     my ($signal, @services) = @_;                                              
465     @services = get_service_list_from_files() unless @services;     
466
467     do_signal_send($_, $signal) for @services;
468
469     # if user passed a know non-shutdown signal, we're done.
470     return if $signal =~ /HUP|USR1|USR2/;
471
472     do_signal_wait($_) for @services;
473 }
474
475 # pull all opensrf listener and drone PIDs from 'ps', 
476 # kill them all, and remove all pid files
477 sub do_kill_with_fire {
478     msg("killing with fire");
479
480     my @pids = get_running_pids();
481     for (@pids) {
482         next unless $_ =~ /\d+/;
483         my $proc = `ps -p $_ -o cmd=`;
484         chomp $proc;
485         msg("killing with fire pid=$_ $proc");
486         kill('KILL', $_);
487     }
488
489     # remove all of the pid files
490     my @files = `ls $opt_pid_dir/*.pid 2> /dev/null`;
491     s/^\s*|\n//g for @files;
492     for (@files) {
493         msg("removing pid file $_");
494         unlink $_;
495     }
496 }
497
498 sub get_running_pids {
499     my @pids;
500
501     # start with the listeners, then drones, then routers
502     my @greps = (
503         "ps x | grep 'OpenSRF Listener' ",
504         "ps x | grep 'OpenSRF Drone' ",
505         "ps x | grep 'OpenSRF Router' "
506     );
507
508     $_ .= "| grep -v grep |  sed 's/^\\s*//' | cut -d' ' -f1" for @greps;
509
510     for my $grep (@greps) {
511         my @spids = `$grep`;
512         s/^\s*|\n//g for @spids;
513         push (@pids, @spids);
514     }
515
516     return @pids;
517 }
518
519 sub clear_stale_pids {
520     my @pidfile_services = get_service_list_from_files(1);
521     my @running_pids = get_running_pids();
522     
523     for my $svc (@pidfile_services) {
524         my @pids = get_service_pids_from_file($svc);
525         for my $pid (@pids) {
526             next if grep { $_ eq $pid } @running_pids;
527             my $pidfile = get_pid_file($svc);
528             msg("removing stale pid file $pidfile");
529             unlink $pidfile;
530         }
531     }
532 }
533
534 sub do_stop_services {
535     my @signals = @_;
536     @signals = qw/TERM INT KILL/ unless @signals;
537
538     msg("stopping services for $hostname");
539     my @services = get_service_list_from_files();
540
541     for my $signal (@signals) {
542         my @redo;
543
544         # send the signal to all PIDs
545         do_signal_send($_, $signal) for @services;
546
547         # then wait for them to go away
548         for my $service (@services) {
549             push(@redo, $service) if do_signal_wait($service) == 2;
550         }
551
552         @services = @redo;
553         last unless @services;
554     }
555
556     return 1;
557 }
558
559 sub do_stop_all {
560     my @signals = @_;
561     @signals = qw/TERM INT KILL/ unless @signals;
562
563     do_stop_services(@signals);
564
565     # graceful shutdown requires the presence of the router, so stop the 
566     # router last.  See if it's running first to avoid unnecessary warnings.
567     do_stop('router', $signals[0]) if get_service_pids_from_file('router'); 
568
569     return 1;
570 }
571
572 # daemonize us.  return true if we're the child, false if parent
573 sub do_daemon {
574     return 1 if $opt_no_daemon;
575     my $service = shift;
576     my $pid_file = get_pid_file($service);
577     my $pid = OpenSRF::Utils::safe_fork();
578     if ($pid) { # parent
579         msg("starting service pid=$pid $service");
580         return 0;
581     }
582     chdir('/');
583     setsid();
584     close STDIN;
585     close STDOUT;
586     close STDERR;
587     open STDIN, '</dev/null';
588     open STDOUT, '>/dev/null';
589     open STDERR, '>/dev/null';
590     `echo $$ > $pid_file`;
591     return 1;
592 }
593
594 # parses the local settings file
595 sub load_settings {
596     my $conf = OpenSRF::Utils::Config->current;
597     my $cfile = $conf->bootstrap->settings_config;
598     return unless $cfile;
599     my $parser = OpenSRF::Utils::SettingsParser->new();
600     $parser->initialize( $cfile );
601     $OpenSRF::Utils::SettingsClient::host_config =
602         $parser->get_server_config($conf->env->hostname);
603 }
604
605 sub msg {
606     my $m = shift;
607     print "* $m\n" unless $opt_quiet;
608 }
609
610 sub do_help {
611     print <<HELP;
612
613     Usage: $0 --localhost --start-all
614
615     --config <file> [default: @CONF_DIR@/opensrf_core.xml]
616         OpenSRF configuration file 
617         
618     --pid-dir <dir> [default: @PID_DIR@/run/opensrf]
619         Directory where process-specific PID files are kept
620
621     --settings-startup-pause
622         How long to give the opensrf.settings server to start up when running 
623         in batch mode (start_all).  The purpose is to give plenty of time for
624         the settings server to be up and active before any non-Perl services
625         attempt to connect.
626
627     --localhost
628         Force the hostname to be 'localhost', instead of the fully qualified
629         domain name for the machine.
630
631     --service <service>
632         Specifies which OpenSRF service to control
633
634     --quiet
635         Do not print informational messages to STDOUT 
636
637     --no-daemon
638         Do not detach and run as a daemon process.  Useful for debugging.  
639         Only works for Perl services and only when starting a single service.
640
641     --help
642         Print this help message
643
644     --diagnostic
645         Print information about running services
646
647     ==== starting services =====
648
649     --start-all
650         Start the router and all services
651
652     --start
653         Start the service specified by --service
654
655     --start-services
656         Start all services but do not start any routers
657
658     --restart-all
659         Restart the router and all services
660
661     --restart
662         Restart the service specified by --service
663
664     --restart-services
665         Restart all services but do not restart any routers
666
667     --force-clean-process
668         When starting a service, if a service process is already running 
669         but no pidfile exists, kill the service process before starting
670         the new one. This applies to routers too.
671
672     --ignore-orphans
673         When starting a service, if a service process is already running but
674         no pidfile exists, ignore the existing process and carry on starting
675         the new one (i.e., ignore orphans).  This applies to routers too.
676
677     ==== stopping services =====
678
679     --stop-all
680         Stop the router and all services.  Services are sent the TERM signal,
681         followed by the INT signal, followed by the KILL signal.  With each
682         iteration, the script pauses up to --signal-timeout seconds waiting
683         for each process to die before sending the next signal.
684
685     --stop
686         Stop the service specified by --service.  See also --stop-all.
687         If the requested service does not have a matching PID file, an
688         attempt to locate the PID via 'ps' will be made.
689
690     --stop-services
691         Stop all services but do not stop any routers.  See also --stop-all.
692
693     --graceful-shutdown-all
694         Send TERM signal to all services + router
695
696     --graceful-shutdown
697         Send TERM signal to the service specified by --service
698
699     --fast-shutdown-all
700         Send INT signal to all services + router
701
702     --fast-shutdown
703         Send INT signal to the service specified by --service
704
705     --immediate-shutdown-all
706         Send KILL signal to all services + router
707
708     --immediate-shutdown
709         Send KILL signal to the service specified by --service
710
711     --kill-with-fire
712         Send KILL signal to all running services + routers, regardless of 
713         the presence of a PID file, and remove all PID files indiscriminately.  
714
715     ==== signaling services =====
716
717     --signal-all
718         Send signal to all services
719
720     --signal
721         Name of signal to send.  If --signal-all is not specified, the 
722         signal will be sent to the service specified by --service.
723
724     --signal-timeout
725         Seconds to wait for a process to die after sending a shutdown signal.
726         All signals except HUP, USR1, and USR2 are assumed to be shutdown signals.
727
728     ==== special signals ====
729
730     --router-de-register
731     --router-de-register-all
732         Sends a SIGUSR1 signal to the selected service(s), which causes each 
733         service's listener process to send an "unregister" command to all 
734         registered routers.  The --all variant sends the signal to all 
735         running listeners.  The non-(--all) variant requires a --service.
736
737     --router-re-register
738     --router-re-register-all
739         Sends a SIGUSR2 signal to the selected service(s), which causes each 
740         service's listener process to send a "register" command to all 
741         configured routers.  The --all variant sends the signal to all
742         running listeners.  The non-(--all) variant requires a --service.
743
744     --reload
745     --reload-all
746         Sends a SIGHUP signal to the selected service(s).  SIGHUP causes
747         each listener process to reload its opensrf_core.xml config file 
748         and gracefully re-launch drone processes.  The -all variant sends
749         the signal to all services.  The non-(-all) variant requires a
750         --service.
751 HELP
752 exit;
753 }
754
755 # we do not verify services for stop/signal actions, since those may
756 # legitimately be used against services not (or no longer) configured
757 # to run on the selected host.
758 do_init() and verify_services($opt_service) if
759     ($opt_start or
760     $opt_start_all or
761     $opt_start_services or
762     $opt_restart or
763     $opt_restart_all or
764     $opt_restart_services) and (
765         not defined $opt_service or $opt_service ne 'router'
766     );
767
768 # starting services.  do_init() handled above
769 do_start($opt_service) if $opt_start;
770 do_stop($opt_service) and do_start($opt_service) if $opt_restart;
771 do_start_all() if $opt_start_all;
772 do_start_services() if $opt_start_services;
773 do_stop_all() and do_start_all() if $opt_restart_all;
774 do_stop_services() and do_start_services() if $opt_restart_services;
775
776 # stopping services
777 do_stop($opt_service) if $opt_stop;
778 do_stop_all() if $opt_stop_all;
779 do_stop_services() if $opt_stop_services;
780 do_stop($opt_service, 'TERM') if $opt_shutdown_graceful;
781 do_stop($opt_service, 'INT') if $opt_shutdown_fast;
782 do_stop($opt_service, 'KILL') if $opt_shutdown_immediate;
783 do_stop_all('TERM') if $opt_shutdown_graceful_all;
784 do_stop_all('INT') if $opt_shutdown_fast_all;
785 do_stop_all('KILL') if $opt_shutdown_immediate_all;
786 do_kill_with_fire() if $opt_kill_with_fire;
787
788 # signaling
789 $opt_signal = 'USR1' if $opt_router_de_register or $opt_router_de_register_all;
790 $opt_signal = 'USR2' if $opt_router_re_register or $opt_router_re_register_all;
791 $opt_signal = 'HUP'  if $opt_reload or $opt_reload_all;
792
793 do_signal($opt_service, $opt_signal) if $opt_signal and $opt_service;
794 do_signal_all($opt_signal) if 
795     $opt_signal_all or 
796     $opt_reload_all or
797     $opt_router_de_register_all or 
798     $opt_router_re_register_all;
799
800 # misc
801 do_diagnostic() if $opt_diagnostic;
802
803
804 # show help if no action was requested
805 do_help() if $opt_help or not (
806     $opt_start or 
807     $opt_start_all or 
808     $opt_start_services or 
809     $opt_stop or 
810     $opt_stop_all or 
811     $opt_stop_services or 
812     $opt_restart or 
813     $opt_restart_all or 
814     $opt_restart_services or 
815     $opt_signal or 
816     $opt_signal_all or
817     $opt_shutdown_graceful or
818     $opt_shutdown_graceful_all or
819     $opt_shutdown_fast or
820     $opt_shutdown_fast_all or
821     $opt_shutdown_immediate or
822     $opt_shutdown_immediate_all or
823     $opt_kill_with_fire or
824     $opt_diagnostic
825 )