#!/usr/bin/perl
### BEGIN INIT INFO
# Provides:          ebox 
# Required-Start:    networking 
# Required-Stop:     networking
# Default-Start:     2 3 4 5
# Default-Stop:      0 6
# Short-Description: eBox platform (network services framework) 
### END INIT INFO

use strict;
use warnings;

use EBox::Global;
use EBox;
use EBox::Sudo;
use File::Slurp;
use Error qw(:try);

EBox::init();
my $global = EBox::Global->getInstance(1);

sub moduleList {
    print "Module list: \n";
    my @mods = @{$global->modInstancesOfType('EBox::Module::Service')};
    my @names = map { $_->{name} } @mods;
    print join(' ', @names);
    print "\n";
}

sub usage {
	print "Usage: $0 start|stop|restart\n";
	print "       $0 <module> start|stop|status|enabled|restart\n";
	exit 1;
}

sub checkModule {
    my ($modname) = @_;
    my $mod = $global->modInstance($modname);
    if (!defined $mod) {
        print STDERR "$modname is not a valid module name\n";
        moduleList();
        exit 2;
    }
    if(!$mod->isa("EBox::Module::Service")) {
        print STDERR "$modname is a not manageable module name\n";
        moduleList();
        exit 2;
    }
    return $mod;
}

sub start() {
    my @mods = @{$global->modInstancesOfType('EBox::Module::Service')};
	my @names = map { $_->{'name'} } @mods;
    @names = grep { $_ ne 'apache' } @names;
	push(@names, 'apache');

	foreach my $modname (@names) {
	  moduleAction($modname, 'restartService', 'start');
	}
}

sub stop() {
    my @mods = @{$global->modInstancesOfType('EBox::Module::Service')};
	my @names = map { $_->{'name'} } @mods;
    @names = grep { $_ ne 'apache' } @names;
	push(@names, 'apache');

	foreach my $modname (@names) {
	  moduleAction($modname, 'stopService', 'stop');
	}
}


sub moduleAction
{
  my ($modname, $action, $actionName) = @_;
  my $mod = checkModule($modname); #exits if module is not manageable

  # Do not restart apache if we are run under ebox-software
  if ($actionName eq 'restart' and $modname eq 'apache' ) {
	return if (exists $ENV{'EBOX_SOFTWARE'} and $ENV{'EBOX_SOFTWARE'} == 1 );
  }

  if ($actionName eq 'start' and $modname eq 'network' and $mod->isEnabled()) {
      try {
        workaroundDHCPIssue();
        EBox::Sudo::root("/etc/init.d/networking stop");
        workaroundDHCPIssue();
      } otherwise {};
  }

  my $success;
  my $errorMsg;
  try {
    $mod->$action();
    $success = 0;
  }
  catch EBox::Exceptions::Base with {
      my $ex = shift;
      $success = 1;
      $errorMsg =  $ex->text();
  } otherwise {
      my ($ex) = @_;
      $success = 1;
      $errorMsg = "$ex";
  };

  printModuleMessage($modname, $actionName, $success, $errorMsg);
}

sub status
{
  my ($modname, $action, $actionName) = @_;

  my $mod = checkModule($modname); #exits if module is not manageable
  
  my $status;
  my $msg = "EBox: status module $modname:\t\t\t";
  if ($mod->isEnabled()) {
   print STDOUT $msg . "[ ENABLED ]\n";
   exit 0;
  } else {
   print STDOUT $msg . "[ DISABLED ]\n";
   exit 3;
  }

}

sub _logActionFunction
{
	my ($action, $success) = @_;
	system(". /lib/lsb/init-functions; " . 
	       " log_begin_msg \"$action\"; log_end_msg $success");
}



sub printModuleMessage
{
  my ($modname, $action, $success, $errorMsg) = @_;
  
  my %actions = ( 'start' => 'Starting', 'stop' => 'Stopping', 
		  'restart' => 'Restarting' );

  my $msg = $actions{$action} . " eBox module: $modname";
  _logActionFunction($msg, $success);
  if ($errorMsg) {
    print STDERR $errorMsg, "\n";
  }
}


sub moduleRestart {
  my ($modname) = @_;

  moduleAction($modname, 'restartService', 'restart');
}

sub moduleStop {
  my ($modname) = @_;
 
  moduleAction($modname, 'stopService', 'stop');
}

sub main
{
  if (@ARGV == 1) {
    if ($ARGV[0] eq 'start') {
      start();
    } 
    elsif ($ARGV[0] eq 'restart') {
      stop();
      start();
    }
    elsif ($ARGV[0] eq 'force-reload') {
      stop();
      start();
    } 
    elsif ($ARGV[0] eq 'stop') {
      stop();
    } else {
      usage();
    }
  } 
  elsif (@ARGV == 2) {
    # action upon one module mode
    my ($modName, $action) = @ARGV;

    if (($action eq 'restart') or ($action eq 'start')) {
      moduleRestart($modName);
    } 
    elsif ($action eq 'stop') {
      moduleStop($modName);
    } elsif ($action eq 'status' or $action eq 'enabled') {
      # FIXME: Separate enabled and status actions
      status($modName);
    } else {
      usage();
    }
  } 
  else {
    usage();
  }
}

# This two methods are used to workaround an issue
# with DHCP configured interfaces when the machine boots.
#
# - System boots
# - /etc/init.d/networking is run asynchronously
# - eBox starts
# - eBox network stops /etc/init.d/networking to take care of the net conf
# - Problem: we can run into race conditions because the way ubuntu starts
#   networking in hardy
# 
# - Approach: we make sure that there isnt any dhclient running before
#   taking care of the network configuration
sub workaroundDHCPIssue() 
{
    my $network = $global->modInstance('network');
    my $dhcp = 0;
    for my $iface (@{$network->allIfaces()}) {
        next unless ($network->ifaceMethod($iface) eq 'dhcp');
        $dhcp = 1;
    }
    # Let's see if there's any ifup running
    if ($dhcp) {
        for (1..200) {
            my $pid = `pgrep  -f "^dhclient3 .*"`;
            my $dhclient;
            if ($? ==  0) {
                EBox::Sudo::root("kill $pid");	
                $dhclient = 1;
            }
            if ($dhclient or anyDhclientPid()) { 
                sleep(5);
            }
        }
    }

}

sub anyDhclientPid
{

    for my $file (read_dir('/var/run')) {
        next unless ($file =~ /dhclient\..*\.pid/);
        if ( -s $file ) {
            return 1;
        }
    }

    return 0;
}

main();

1;
