#! /usr/bin/perl -w
# My personal script to manage to NWS familly of daemons.
# Contrary to the upstream provided scripts, it does not
#  try to manage all the machines on the net. It only
#  manage the scripts on the locale machine, but it does
#  it well. It has a conffile (usually /etc/nws.conf),
#  in which you can set a great lot of things.
# To manage the whole net, it is easy to do scripts like
#  the next one to pass a command to each site :
#
#--BEGIN
##! /bin/sh
## To be run as cron table on only on machine
#
#machines="<space separed list of your machines>"
#for n in `echo $machines` ; do
#  cmd="rsh $n /path/to/nws_setup $@";
#  echo " $cmd";
#  system($cmd);
#  echo;
#done;
#--END
#
# Copyright (C) 1999 Free Software Foundation, Inc.
# Martin Quinson <mquinson@ens-lyon.fr>, 2000,2001,2002.
# Distributed under the GPL Licence. 
#

# TODO: 
#  - Searching the bin path after parsing the config file, we wouldn't 
#    have to hardcode the name of binaries
#  - What if all binaries are not in the same directory?
#  - for now, logpath and statpath are the first writable dir from 
#    hardcoded lists. Need for a better tests?
#  - Allow being in several groups
#  - check that handling of empty value in config file is correct
#  - generalize the skills

use strict;
use POSIX 'setsid'; #to fork daemons
use IO::Handle; #just to flush...

my $conffile=""; # Where to read the args from
my $progname = $0; $progname= $& if $progname =~ m,[^/]+$,;

#
# Parse command line
#
my $verbose=0; # do I have to tell my life to user or should I shut up ?
my $gdb_attach=0;
my $whereconf="/etc/nws.conf $ENV{HOME}/.nws.conf $ENV{HOME}/etc/nws.conf /usr/local/etc/nws.conf";

my $opt;
for ($opt = shift @ARGV; $opt =~ /^--?(.*)$/; $opt = shift @ARGV) {
    my $optname = $1;
    if ($optname =~ /gdb/) {
	$gdb_attach = 1;
    } elsif ($optname =~ /verbose/ || $optname =~ /^v$/) {
	$verbose = 1;
    } elsif ($optname =~ /conffile/ || $optname =~ /^c$/) {
	$whereconf= shift @ARGV;
    }
}
unshift @ARGV,$opt;


#
# Search the conffile
# 
my $i;

foreach $i (split(/\s+/,$whereconf)) {
    if (("$conffile" eq "")&&(-s $i)) {
	$conffile=$i;
    }
}
if (-z "$conffile") {
    die ("$progname: Can't find my conffile ! I've searched in :\n  $whereconf\n  Please create one, or edit the script !\n");
}

sub empty {
    my $aze=shift;
    return 1 unless (defined $aze);
    return 1 unless ($aze =~ m,\S,);
    return 0;
}

#####################
# Read all the args #
#####################

# Who am I ?
my $hostname; # this machine
my $my_group=undef; # Group of which this machine is member

# Meta configuration
my ($possible_actions,$possible_infos,$possible_skills,
    $possible_parts,$possible_stop);
my %howto; # $howto{cat}{part} is the cmd to exec to $cat'ing $part
           #  Valid value to cat are: start, stop and test
my %skills; # keys=name of skills to run;values=args for them FIXME?

# Content of config file
my %config; # actual value of each variable


# What should I do here ?
my $start_part; # ordoned list of parts to start
my $stop_part; # idem, to stop

# FIXME: Old cruft ? 
# my $ctrl_host; #the prog to check the daemons
my $start_activity; #the prog to check the skills


##
## Get a variable from the configuration file, or from the provided
##  defaults. Defaults may content several possibilities, separated by '||'
##  Each part can be '$ENV{"something"}' or a fixed string.
##
sub arg {
    my $name=shift;
    my $defaults=shift;

    my $line; # to read the conffile

    my $global=undef; # where to put any global corresponding
    my $group=undef;  # where to put setting for my group
    my $partic=undef; # where to put any setting for this particular machine
    my $res;
    
    ##
    ## Parse conf file
    ## 
    open FILE,"$conffile" ||
	die "$progname: Error: can't open the conffile `$conffile'\n";
    while (<FILE>) {
	chomp;
	while ((s/\\$//) && ($_ .= <FILE>)){}
	s/#.*$//;
	next unless /^$name/;
	chomp;
	if (/^$name\s*\(.*?$hostname[^\)]*\)\s*=\s*(.*?)\s*$/) {
	    warn "$progname: Warning: `$name' is set several times for $hostname in `$conffile'\n" 
		if (defined $partic);
	    $partic=$1;
	}
	if (defined $my_group && $my_group && 
	    /^$name\s*\(.*?$my_group[^\)]*\)\s*=\s*(.*?)\s*$/) {
	    warn "$progname: Warning: `$name' is set several times for group $my_group in `$conffile'\n" 
		if (defined $group);
	    $group=$1;
	}
	if (/^$name\s*=\s*(.*?)\s*$/) {
	    warn "$progname: Warning: `$name' is set several times in `$conffile'\n"
		if (defined $global);
	    $global=$1;
	}
    }
    close FILE;
    ##
    ## Get value from what was parsed if possible
    ##
    $res=$partic;
    $res=$group unless (defined $res);
    $res=$global unless (defined $res);

    ## 
    ## Handle defaults
    ##
    if ($defaults) {
	foreach my $defaultpart (split(/\|\|/,$defaults)) {
	    unless (defined($res)) {
		if ($defaultpart =~ /\$ENV\{([^\}]*)\}/) {
		    $res=$ENV{$1} || undef;
		} else {
		    $res=$defaultpart;
		}
	    }
	}
    }
    
    if ($res) {
	my $home="$ENV{HOME}";
	$res =~ s/^~\//$home/;
    }
    return $res;
}


#########################################
### the main function to get the args ###
#########################################
sub read_all_the_args {
    my $dol='$'; # to ease some regular expressions

    ##
    ## Parse the meta-configuration:
    ##  definition of NWS parts and how to run them at the end of 
    ##  this file
    ##

    my %legal_data_value; # what value can be found in the data part
    my %var_defaults; # defaults of each variable

    while (<DATA>) {
	chomp;
	while ((s/\\$//) && ($_ .= <DATA>) && chomp){}
	s/#.*$//;
	next if /^$/;
	die "unparsable metaconfiguration data: $_" 
	    unless (m/^(([^=[:blank:]])*)\s*?=\s*(.*)$/);
	my ($var,$val)=($1,$3);
	# Get info about what is allowed in the rest
	if      ($var =~ /^possible_parts$/) { $possible_parts  = $val;
	} elsif ($var =~ /^possible_stop$/) {  $possible_stop   = $val;
        } elsif ($var =~ /^possible_skills/) { $possible_skills = $val;
        } elsif ($var =~ /^possible_actions/) {$possible_actions= $val;
        } elsif ($var =~ /^possible_infos/) {  $possible_infos  = $val;

        # learn how to handle all parts, and which variables are needed for
        #   that (no other variable will be allowed in config file)
        } elsif ($var =~ /^([^_]*)_(.*)$/ 
		 && (grep {$_ eq $1} split(/ /,$possible_actions))
		 && (grep {$_ eq $2} split(/ /,$possible_parts))) {
	    $howto{$1}{$2}="$val";
	    foreach (split(/ +/,$val)) {
		while (s/^([^$dol]*\$)//) {
		    s/([-_a-zA-Z0-9]*)//;
		    $legal_data_value{$1}=1;
		}
 	    }

	# learn about infos on parts, and which variables are needed for
        #   that (no other variable will be allowed in config file)
        } elsif ($var =~ /^([^_]*)_(.*)$/ 
		 && (grep {$_ eq $1} split(/ /,$possible_parts))
		 && (grep {$_ eq $2} split(/ /,$possible_infos))) {
	    $legal_data_value{$var}=1; # these are always legal
	    $var_defaults{$var}=$val;
	    
	} elsif ($legal_data_value{$var}) {
	    $var_defaults{$var}=$val;
	} else {
	    print "Unparsable metaconfig line: $var=$val\n";
	}
    } 

    ##
    ## search the hostname
    ##

    my $host=`hostname`;
    chomp($host);
    # search the good domainname executable
    my $domainname="";
    if ((-f "/usr/bin/domainname")
	&& system("/usr/bin/domainname 2>&1 >/dev/null")) {
	$domainname="/usr/bin/domainname";
    } elsif ((-f "/bin/dnsdomainname")
	     && system("/bin/dnsdomainname 2>&1 >/dev/null")) {
	$domainname="/bin/dnsdomainname";
    } else {
	warn "Warning : unable to find the domainname\n" if $verbose;
    }
    if ("$domainname" ne "") {
	$hostname=`$domainname 2>/dev/null`;
	if ("$hostname" eq "") {
	    $hostname="$host";
	} else {
	    $hostname="$host.$hostname";
	}
    } else {
	$hostname="$host";
    }
    chomp($hostname);
    my $old_name = $hostname;
    # Get the verbosity from the config file
    $verbose ||= arg("verbose","0");
    $hostname=arg("hostname","$hostname");
    if ($hostname eq $old_name) {
	warn("DEBUG: My name is $hostname\n") if $verbose;
    } else {
	warn("My name is $hostname (was $old_name)\n") if $verbose;
    }
    $config{'hostname'}="$hostname";

    ##
    ## Am I member of a group ?
    ## 
    $my_group=arg("group") || "";    

    ##
    ## Search the bin path 
    ##
    my $bin_path="";
    foreach my $pathpart (split(':',$ENV{PATH})) {
	if (-x "$pathpart/nws_sensor" &&
	    -x "$pathpart/nws_nameserver" &&
	    -x "$pathpart/nws_memory" &&
	    -x "$pathpart/nws_ctrl" &&
	    (-x "$pathpart/nws_start_activity"|| -x "$pathpart/start_activity")) {
	    $bin_path=$pathpart;
	    last;
	} 
    }
    unless ($bin_path =~ /\W/) {
	die "Unable to find the nws binaries in your PATH. Please fix it.\n";
    }
    $config{'bin_path'}="$bin_path";
    
    # 
    # Search the log path
    #
    my $log_path="";
    my $path_test=(arg("log_path")||"")." /var/log/nws $ENV{HOME}/var/log/nws $ENV{HOME}/var/log/ /tmp";
    LOGPATH: foreach my $pathpart (split(" ",$path_test)) {
	if (-w "$pathpart") {
	    $log_path=$pathpart;
	    last;
	}
    }
    if (-z $log_path) {
	die "Unable to write logs to either $path_test. Please fix it\n";
    }
    $config{'log_path'}="$log_path";

    #
    # Search the state path
    #
    my $state_path="";
    $path_test=(arg("state_path")||"")." /var/state/nws $ENV{HOME}/var/state/nws $ENV{HOME}/var/state $log_path /tmp";
    LOGPATH: foreach my $pathpart (split(" ",$path_test)) {
	if (-w "$pathpart") {
	    $state_path=$pathpart;
	    last;
	}
    }
    if (-z $state_path) {
	die "Unable to write stat to either $path_test. Please fix it\n";
    }
    $config{'state_path'}="$state_path";

    # The rest is to ensure compatibility with upstream binaries 
    #  whose name where not prefixed with 'nws_' by me.
    if (-x "$bin_path/nws_start_activity") {
	$start_activity="$bin_path/nws_start_activity";
    } else { # must exist since we tested it for bin_path
	$start_activity="$bin_path/start_activity";
    }

    ##
    ## And now, read the args for all parts
    ##  We search in the config file, and what we search was parsed from
    ##  the end of this file.
    ##
    foreach my $var (sort keys %legal_data_value) {
#	printf "var=%s ; defaults=%s ; preset value=%s\n",
#  	  ($var ? $var:"UNDEF"),
#	  ($var_defaults{$var} ? $var_defaults{$var}:"UNDEF"),
#	  ($config{$var} ? $config{$var} : "UNDEF");
	$config{$var}=arg($var,$var_defaults{$var})
	    unless (defined $config{$var});
    }
#    foreach my $var (sort keys %config) {
#	print "$var=".($config{$var}||"***** UNDEF *****")."\n";
#    }

    ## 
    ## Ok, we can now rewrite the variables, to remove all reference to 
    ##  other variables in variable body ($a=AZE;$b=$a.$a)->($a=AZE;$b=AZE.AZE)
    ##
    my $errmsg_undef = "Error: '%s' is undef. The config file must provide a value.\n";

    foreach my $var (sort keys %config) {
	my $dol = '$';
#	print STDERR "Look at $var=".($config{$var}||"***** UNDEF *****")."\n";
	die sprintf ($errmsg_undef,$var) unless (defined $config{$var});
	while ($config{$var} =~ m/^([^$dol]*?)\$([-_a-zA-Z0-9]*)(.*)$/) {
	    die sprintf ($errmsg_undef,$2) unless (defined $config{$2} || length($2)==0);
	    $config{$var} = $1.(length($2)?$config{$2}:"").$3;
	}
    }
    
    ##
    ## Rewrite start, test, stop command lines.
    ## 
    foreach my $part (split(/ /,$possible_parts)) {
	foreach my $cat (split(/ /,$possible_actions)) {
	    die "Error in meta-configuration: Dunno how to $cat $part\n"
		unless ($howto{$cat}{$part});
	    while ($howto{$cat}{$part} =~ m/^([^$dol]*?)\$([-_a-zA-Z0-9]*)(.*)$/) {
		die sprintf ($errmsg_undef,$2) unless (defined $config{$2});
		$howto{$cat}{$part} = $1.$config{$2}.$3;
	    }	    
	}
    }
    ##
    ## Check that all info is defined
    ##
    foreach my $part (split(/ /,$possible_parts)) {
	foreach my $info (split(/ /,$possible_infos)) {
	    warn "Error in meta-configuration: info '$info' not present for '$part'.\n"
		unless defined $config{$part.'_'.$info};
	}
    }
    ##
    ## Read the args about the skills
    ##

    # read it
    my $skills=arg("skills");

    # verify it
    if (defined $skills) {
	foreach my $j (split(/\s+/,$skills)) {
	    my $good="no";
	    foreach $i (split(/\s+/,$possible_skills)) {
		$good="yes" if ($i eq $j);
	    }
	    ($good eq "yes") || 
		die "$progname: Error: Skill `$j' unknown.\n";
	    
	    # read the args of skills
	    $skills{$j}=arg("skill.$j");
	    unless (defined $skills{$j}) {
		$skills{$j}="";
	    }
#	printf "args of $j=${skills{$j}}\n";
	}
    }
}

#
# read and verify part_to_run
#

sub verify_part {
    #read it
    my $part_to_run=shift;
    $part_to_run=arg("part_to_run") unless (defined($part_to_run));

    die "Nothing to do (part_to_run is empty)\n"
	unless (defined($part_to_run) && $part_to_run);
    #verify it
    foreach my $j (split(/\s+/,$part_to_run)) {
	my $good="no";
	foreach $i (split(/\s+/,$possible_parts)) {
	    $good="yes" if ($j =~ /^$i(:[0-9]*)?$/);
	}
	($good eq "yes") || 
	    die "$progname: Error: I don't know the part `$j' of NWS.\n";
    }

    # sort it
    $start_part="";
    foreach $i (split(/\s+/,$possible_parts)) {
	$start_part="$start_part $1" if ($part_to_run=~ m,($i(:[0-9]*)?),);
    }

    $stop_part="";
    foreach $i (split(/\s+/,$possible_stop)) {
	$stop_part="$stop_part $1" if ($part_to_run=~ m,($i(:[0-9]*)?),);
    }    

    # trim it
    $start_part=~ s/^\s*(.*?)\s*$/$1/;
    $stop_part=~ s/^\s*(.*?)\s*$/$1/;
}

sub launch_skills {
    my $cmd;
    return 0 unless ($start_part =~ m,sensor,);
    sleep(5); # Make sure the sensor had enough time to start
    SKILL: foreach my $i (sort keys %skills) {
#	printf "  (re)launch the $i skill: ";
#	$cmd="$start_activity -F start $name{sensor} $i ${skills{$i}} ";
	$cmd="$start_activity -F $config{sensor_name} skillName:$i ${skills{$i}} ";
#	printf ("\n(Launch the skill with `$cmd')\n");
	if (system($cmd)){
	    # system returns "does something go wrong ?"
#	    if (system("$start_activity restart $name{sensor} $i ${skills{$i}} 1>/dev/null")) {
		printf "failed.\n";
		next SKILL;
#	    }
	}
#	printf "done.\n";
    }
}

sub fork_and_exec {
    my $cmd=shift;
    my $pid=fork;
    (defined $pid) || printf "Can't fork: $!\n";
    if ($pid) {
	#father
	printf("Forked to exec '$cmd'\n") if $verbose;
	if ($gdb_attach) {
	    printf("\n\nAttaching gdb to pid $pid");
	    exec split (' ',"gdb --pid $pid");
	}
    } else {
	#child
	setsid || die "Can't start a new session: $!";
	exec split(' ',$cmd);
    }
}

sub test {
    my $part=shift;

    my $res=qx,$howto{'test'}{$part},;
    chomp($res);
    $res=~ s/^.*?\s(\S*)$/$1/;
    return $res;
}

sub usage {
    die "$progname: Usage:  $progname [<options>] <command> [<part>]\n".
	"  where <command> is one of the following (unquoted):\n".
	"   'config' : display the configuration of this machine\n".
	"   'revive': Test if the daemons are dead, and try to launch them if needed.\n".
	"   'start': do not test anything, just try to launch the daemons.\n".
	"   'stop': Ask the daemon to die.\n".
	"   'restart': Synonym for 'stop' and then 'start'\n".
	"   'term': send SIGTERM to the daemon (which must be yours,\n".
	"                           unless you're root).\n".
	"   'kill': send SIGKILL to the daemon (which must be yours,\n".
	"                           unless you're root).\n".
        "   'test': display the state of the daemons.\n".
	"  if <part> is given, only applies to this part. It can be a *quoted* spaces separed list.\n".
	"    Autorized values : ".($possible_parts||"")."\n".
        "  <options> can be:\n".
        "    --conffile, -c\n".
        "           Use the given file as conffile\n".
        "    --gdb  When used in conjonction with 'start', only the first process will be launched, and\n".
        "           a gdb session will be attached to it\n".
        "    --verbose, -v\n".
        "           Run in verbose mode\n";
      
}

my $cmd = shift;
(defined $cmd) || usage;

read_all_the_args();
verify_part(shift);

my $pid; # to fork
my $status;

STDOUT->autoflush(1);


SWITCH: {
    #
    # config command
    #
    if ($cmd eq 'config') {
	my $err=0;
	print "Used configuration file: $conffile\n";
	print "Path to binaries used: '".$config{'bin_path'}."'\n";
    	print "This machine is named '$hostname'";
	if ($my_group) {
	    print ", and belongs to group '$my_group'\n";
	} else {
	    print ", and don't belong to any group.\n";
	}
	
	print "\nParts to run:\n $start_part (out of: $possible_parts)\n";
	foreach my $part(split(/ /,$possible_parts)) {
	    foreach my $cat (split(/ /,$possible_actions)) {
		my $cmd=$howto{$cat}{$part};
		$cmd =~ s/\s+/ /g;
		print "  Cmd to $cat a $part: '$cmd'\n";
	    }
	    print "\n";
	}
	my $skills=arg("skills");
	print "Skills to use:\n $skills (out of: $possible_skills)\n";
	$skills =~ s/ //g;
	if ($skills ne '' && !($start_part =~ /sensor/)) {
	    print "*** ERROR: Requested to run skills without sensor ***\n";
	    $err++;
	}
	print "\n";
	
	foreach my $servername (qw(nameserver memory)) {
	    my $server = $config{"$servername"};
	    $server =~ s/:.*//;
	    print "Check whether the $servername (on $server) is routable: ";
	    my $out = `ping -c 1 $server 2>&1`;
	    if ($? >> 8) {
		print "no !!\n*** ERROR: This machine cannot connect to the $servername ***\n";
		print "====[ 'ping -c 1 $server' output begin ]====\n$out\n====[ 'ping  -c 1 $server' output end ]====\n";
		print "You cannot use NWS without first fixing /etc/hosts (or equivalent).\n";
		$err++;
	    } else {
		print "yes.\n";
	    }
	}
	my $server = $config{"hostname"};
	print "Check whether it is possible to contact this machine from itself: ";
	my $out = `ping -c 1 $hostname 2>&1`;
	if ($? >> 8) {
		print "no !!\n*** ERROR: This machine cannot connect to itself ***\n";
		print "====[ 'ping -c 1 $server' output begin ]====\n$out\n====[ 'ping  -c 1 $server' output end ]====\n";
		print "You cannot use NWS without first fixing /etc/hosts (or equivalent).\n";
		$err++;
	} else {
		print "yes.\n";
	}
	if ($err) {
	    die "\n*** $err ERROR".($err>1?"S WERE":" WAS")." DETECTED ***\n";
	}
	last SWITCH;
    }
    #
    # Test command
    #
    if ($cmd eq "test") {
	printf "Testing NWS on $hostname:\n",;
	foreach $i (split(/\s+/,$start_part)) {
	    print "  Testing the NWS $i on ".$config{$i.'_name'}.": ";
	    print test($i).".\n";
	}
	last SWITCH;
    }
    #
    # Start command
    #
    if ($cmd eq "start") {
	printf "Starting the NWS family on $hostname:";
	foreach $i (split(/\s+/,$start_part)) {
	    printf " $i";
	    fork_and_exec($howto{'start'}{$i});
	}
	printf ".\n";
	launch_skills;
	last SWITCH;
    }
    #
    # log control
    #
    if ($cmd eq "log") {
	print "Toggle the NWS log production on $hostname:";
	foreach $i (split(/\s+/,$stop_part)) {
	    fork_and_exec($howto{'log'}{$i});
	    print " $i";
	}
	print ".\n";
	last SWITCH;
    }
    #
    # revive
    #
    if ($cmd eq "revive") {
	printf "Reviving the NWS family on $hostname:";
	PART: foreach $i (split(/\s+/,$start_part)) {
	    printf " $i";
	    $status=test($i);
	    if ($status eq "healthy") {
		print "(ok)";
		next PART;
	    } else {
		print "($status->" if $verbose;
		if ($status ne "dead") {
		    qx,$howto{'stop'}{$i},;
		}
		fork_and_exec($howto{'start'}{$i});
		WAIT: for (my $j=0;$j<10;$j++){
		    $status=test($i);
		    sleep 1; #waiting a while before testing it...
		    last WAIT if ($status eq "healthy");
		    print "." if $verbose;
		}
		print "$status)" if $verbose;
                print "($status)" unless $verbose;
	     }
	}
	print ".\n";
	launch_skills;
	last SWITCH;
    }
    #
    # Stop commands
    #
    if ($cmd eq "stop") {
	printf "Stopping the NWS family on $hostname:";
	foreach $i (split(/\s+/,$stop_part)) {
	    printf " $i";
	  WAIT: for (my $j=0;$j<10;$j++){
	      qx,$howto{"stop"}{$i},;
	      $status=test($i);
	      last WAIT if ($status eq "dead");
	      printf "." if $verbose;
	      sleep 1;
	  }
	}
	print ".\n";
	last SWITCH;
    }
    if ($cmd =~ m,term,) {
	printf "Sending the TERM signal to the NWS familly on $hostname:";
	foreach $i (split(/\s+/,$stop_part)) {
	    printf " $i";
	    if (-e $config{$i.'_pidfile'}) {
		my $pid=`cat $config{$i.'_pidfile'}`;
		chomp $pid;
		system("kill -TERM $pid");
	    } else {
		print "(pidfile not found)";
	    }
	}
	printf ".\n";
	last SWITCH;
    }
    if ($cmd =~ m,kill,) {
	printf "Sending the KILL signal to the NWS familly on $hostname:";
	foreach $i (split(/\s+/,$stop_part)) {
	    printf " $i";
	    if (-e $config{$i.'_pidfile'}) {
		my $pid=`cat $config{$i.'_pidfile'}`;
		chomp $pid;
		system("kill -KILL $pid");
		unlink($config{$i.'_pidfile'});
	    } else {
		print "(pidfile not found)";
	    }
	}
	printf ".\n";
	last SWITCH;
    }
    # 
    # Restart commands
    #
    if (($cmd eq "restart")||($cmd eq "cycle")) {
	system("$0 stop \"$start_part\"");
	printf("  (Waiting every part of NWS to stop...") if $verbose;
      WAIT: for (my $j=0;$j<10;$j++){
	  foreach $i (split(/\s+/,$start_part)){
	      $status=qx,$howto{"test"}{$i},;
	      if ($status eq "healthy") {
		  printf "." if $verbose;
		  sleep (1);
		  next WAIT;
	      }
	  }
	  printf " Done).\n" if $verbose;
	  last WAIT;
	  printf (".") if $verbose;
      }
	system("$0 start \"$stop_part\"");
	last SWITCH;
    }
    usage();
}

exit 0;

__DATA__
##
## This is the meta configuration
##  Warning: this is NOT perl. No ';' needed
##
possible_actions=start test stop log
possible_infos=name pidfile
# which process are runnable ?
possible_parts=nameserver memory sensor forecaster#in order of launching
possible_stop=forecaster sensor memory nameserver #in order of stoping
possible_skills=tcpMessageMonitor tcpConnectMonitor cpuMonitor memoryMonitor diskMonitor

# command line to start,test,stop each process
start_nameserver=$nameserver_bin -p $nameserver_port -v 5 \
                 -e $nameserver_errfile -l $nameserver_logfile -i $nameserver_pidfile \
                 -f $nameserver_state -c $nameserver_expire \
                  1>>$nameserver_logfile 2>>$nameserver_errfile
test_nameserver=$nws_ctrl -t 3 test $nameserver_name
stop_nameserver=$nws_ctrl -t 3 halt $nameserver_name
log_nameserver=$nws_ctrl -t 3 log $nameserver_name

start_memory=$memory_bin -N $nameserver -v 5 \
             -p $memory_port -d $memory_state -s $memory_size \
             -e $memory_errfile -l $memory_logfile -i $memory_pidfile 1>>$memory_logfile 2>>$memory_errfile
test_memory=$nws_ctrl -t 3 test $memory_name
stop_memory=$nws_ctrl -t 3 halt $memory_name
log_memory=$nws_ctrl -t 3 log $memory_name

start_sensor=$sensor_bin -N $nameserver -M $memory -v 5 \
             -p $sensor_port -c $sensor_cpu \
             -e $sensor_errfile -l $sensor_logfile -i $sensor_pidfile 1>>$sensor_logfile 2>>$sensor_errfile
test_sensor=$nws_ctrl -t 3 test $hostname:$sensor_port
stop_sensor=$nws_ctrl -t 3 halt $hostname:$sensor_port
log_sensor=$nws_ctrl -t 3 log $hostname:$sensor_port

start_forecaster=$forecaster_bin -N $nameserver -p $forecaster_port \
                 -e $forecaster_errfile -l $forecaster_logfile -i $forecaster_pidfile \
                 1>>$forecaster_logfile 2>>$forecaster_errfile
test_forecaster=$nws_ctrl -t 3 test $forecaster_name
stop_forecaster=$nws_ctrl -t 3 halt $forecaster_name
log_forecaster=$nws_ctrl -t 3 log $forecaster_name


## default values about processes (should correspond to the cmd line args above)
# (globals)
nameserver=$ENV{NAME_SERVER}||$hostname:$nameserver_port
memory=$hostname:$memory_port

# (info about all part)
nameserver_bin=$bin_path/nws_nameserver
nameserver_port=$ENV{NAME_SERVER_PORT}||8090
nameserver_state=$state_path/nameserver.$hostname.$nameserver_port.registrations
nameserver_expire=3600

nameserver_name=$hostname:$nameserver_port
nameserver_errfile=$log_path/nameserver.$hostname.err
nameserver_logfile=$log_path/nameserver.$hostname.log
nameserver_pidfile=$state_path/nameserver.$hostname.pid


nws_ctrl=$bin_path/nws_ctrl

memory_bin=$bin_path/nws_memory
memory_port=$ENV{MEMORY_PORT}||8050
memory_state=$ENV{MEMORY_DIR}||$state_path/memory.$hostname.$memory_port
memory_size=$ENV{MEMORY_SIZE}||2000

memory_name=$hostname:$memory_port
memory_errfile=$log_path/memory.$hostname.$memory_port.err
memory_logfile=$log_path/memory.$hostname.$memory_port.log
memory_pidfile=$state_path/memory.$hostname.$memory_port.pid



sensor_bin=$bin_path/nws_sensor
sensor_port=$ENV{SENSOR_PORT}||8060
sensor_cpu=no

sensor_name=$hostname:$sensor_port
sensor_errfile=$log_path/sensor.$hostname.$sensor_port.err
sensor_logfile=$log_path/sensor.$hostname.$sensor_port.log
sensor_pidfile=$state_path/sensor.$hostname.$sensor_port.pid



forecaster_bin=$bin_path/nws_forecast
forecaster_port=$ENV{FORECASTER_PORT}||8070

forecaster_name=$hostname:$forecaster_port
forecaster_errfile=$log_path/forecaster.$hostname.$forecaster_port.err
forecaster_logfile=$log_path/forecaster.$hostname.$forecaster_port.log
forecaster_pidfile=$state_path/forecaster.$hostname.$forecaster_port.pid
