#!/usr/bin/perl

# The master control program for starting and stopping OpenFPC instances.
#########################################################################################
# Copyright (C) 2010 Leon Ward 
# openfpc - Part of the OpenFPC - (Full Packet Capture) project
#
# Contact: leon@rm-rf.co.uk
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#########################################################################################

use strict;
use warnings;
use Getopt::Long;
use Switch;
use Data::Dumper;
use File::Path qw(mkpath);

my $openfpcver=0.6;
my $conf_dir="/etc/openfpc";

my ($quiet,$usertype,$verbose,$help);
my $init=0;						# init script friendly output (i.e not much!)
my $type=0;
my $thing=0;
my %configs=();						# Hash of all configs in $CONF_DIR;
my @nodes=();						# List if all nodes configured
my $action=0;
my @daemonsNode=("openfpc-daemonlogger", 		# Daemons we want to start in OpenFPC Node mode
		"openfpc-queued",
		"openfpc-cxtracker",
		"openfpc-cx2db" );
my @daemonsNodeNoSession=("openfpc-daemonlogger", 	# Daemons we want to start in OpenFPC Node mode
		"openfpc-queued");			# with ENABLE_SESSION=0

my @daemonsProxy=("openfpc-queued"); 			# Daemons we want to start in OpenFPC proxy mode

my %defaults=(  PIDPATH => "/var/run",
		DAEMONLOGGER_CMD => "/usr/bin/daemonlogger",
		CXTRACKER_CMD => "/usr/bin/cxtracker" ,
		OPENFPC_QUEUED_CMD => "/usr/bin/openfpc-queued",
		SESSION_DIR => "/var/tmp/openfpc/session",
		BUFFER_DIR => "/var/tmp/openfpc/pcap",
		CX2DB_CMD => "/usr/bin/openfpc-cx2db",
		BPF_FILE => 0,
		);

############################################
# End of globals
############################################

=head2  getType
	Unless a user has specified if we are taking action on a daemon, or a configuration, this function will try to autodetect.
	The only real risk of failing to detect is if someone stupidly names a configuration the same name as a daemon
	e.g. NODENAME="openfpc-daemonlogger"

	Expects string
	Returns a hash ...

	(	type => "config",
	  	instance => "instance" ,
		filename => "/etc/openfpc/config.filename",
	)
=cut

sub getType{
	my $thing=shift;
	my %result=( 	type => 0 ,
			instance => 0,
			filename => 0, 
		);
	my @daemons=(	"openfpc-queued",
			"openfpc-daemonlogger",
			"openfpc-cxtracker",
			"openfpc-cx2db");
	
	# Check if thing is one of our known daemons
	foreach(@daemonsNode) {
		if ( $_ eq $thing ) {
			$result{'type'} = "daemon";
			$result{'filename'} = "/etc/init.d/" . $thing;	
			return(\%result);
		}
	}

	# Check if thing is one of our config files
	if ( exists $configs{$thing} ) {
		$result{'type'} = "instance";
		$result{'instance'} = "$thing";
		$result{'filename'} = $thing;
	}

	# Check if thing is a node-name in any of the config files.
	foreach (keys(%configs)) {
		if (defined $configs{$_} ) {
			my $filename=$_;
			if ( $thing eq $configs{$_}{'NODENAME'} ) {
				$result{'type'} = "instance";
				$result{'filename'} = "$filename";
				return(\%result);
			}
		}
	}

	# We don't know what it is.
	return(\%result);	
}

=head2  getInstanceByDaemon
	Get a list of instances that this daemon needs to be started for.
	returns an array of instances (config filenames)
=cut

sub getInstanceByDaemon{
	my $daemon=shift;
	my @instances=();

	foreach my $conf (keys(%configs)) {
		if (defined $configs{$conf}{'OFPC_ENABLED'} ) {
			if ($configs{$conf}{'OFPC_ENABLED'} =~ /(y|yes|1)/i ) {
				if ($configs{$conf}{'PROXY'} == 1) {
					# Enabled Proxy
					if ( grep $_ eq $daemon, @daemonsProxy ) {
						push(@instances, $conf);
					}
				} elsif ($configs{$conf}{'PROXY'} == 0 ) {
					if ($configs{$conf}{'ENABLE_SESSION'} == 1) {
						if ( grep $_ eq $daemon, @daemonsNode ) {
							push(@instances, $conf);
						}
					} else {
						if ( grep $_ eq $daemon, @daemonsNodeNoSession ) {
							push(@instances, $conf);
						}
					}
				}
			}
		}
	}
	return(@instances);
}


=head2 getDaemonsByInstance
	Return a list of daemons we need to start for a config files
=cut

sub getDaemonsByInstance{
	my $instance=shift;
	my @daemons=();
	
	if ($configs{$instance}{'OFPC_ENABLED'} =~ /(y|yes|1)/i ) {
		if ($configs{$instance}{'PROXY'} == 1 ) {
			return(@daemonsProxy);
		} elsif ($configs{$instance}{'PROXY'} == 0  ) {
			if ($configs{$instance}{'ENABLE_SESSION'} == 1) {
				return(@daemonsNode);
			} else {
				return(@daemonsNodeNoSession);
			}
		} else {
			die("Unknown Proxy config for instance: $instance\n");
		}
	} else {
		return(@daemons);
	}
}

=head2 getPidFromFile
	Open a pidfile, and return the pid
=cut

sub getPidFromFile($){
	my $filename=shift;
	my $pid=0;

	if ( -f $filename) {
		open PIDFILE, '<', "$filename" or return(0);
		while(<PIDFILE>) {
			$pid=$_;	
			chomp $pid;
		}
	}
	return($pid); 
}

sub isPidRunning($){
	my $pid=shift;
	if ( system("ps $pid > /dev/null")) {
		return(0);
	} else {
		return(1);
	}
}

=head2 findcmd
	Seach for installed file.
	We need this because /usr/bin/ is really for system provided bins.
	/usr/local/ makes more sense when installing from src.
	I also want to allow user specification in a .conf
	-Leon
	Expects a daemon and an instance.
	Returns the path to the daemon

	e.g. findcmd("openfpc-daemonlogger","openfpc-example.conf");
=cut
sub findcmd{
	my $daemon=shift;
	my $instance=shift;
	my @daemoncmds=();

	switch($daemon) {
		case "openfpc-queued" {
			@daemoncmds=( "$defaults{'OPENFPC_QUEUED_CMD'}",
				"/usr/local/bin/openfpc-queued",
				"/usr/bin/openfpc-queued",
				"./openpfc-queued");
			unshift(@daemoncmds, $configs{$instance}{'OPENFPC_QUEUED_CMD'})  if defined $configs{$instance}{'OPENFPC_QUEUED_CMD'};
		}
		case "openfpc-daemonlogger" {
			@daemoncmds=( "$defaults{'DAEMONLOGGER_CMD'}",
				"/usr/local/bin/daemonlogger",
				"/usr/bin/daemonlogger",
				"./daemonlogger");
			unshift(@daemoncmds, $configs{$instance}{'DAEMONLOGGER_CMD'})  if defined $configs{$instance}{'DAEMONLOGGER_CMD'};
		}
		case "openfpc-cxtracker" {
			@daemoncmds=( "$defaults{'CXTRACKER_CMD'}",
				"/usr/local/bin/cxtracker",
				"/usr/bin/cxtracker",
				"./cxtracker");
			unshift(@daemoncmds, $configs{$instance}{'CXTRACKER_CMD'})  if defined $configs{$instance}{'CXTRACKER_CMD'};
		}
		case "openfpc-cx2db" {
			@daemoncmds=( "$defaults{'CX2DB_CMD'}",
				"/usr/local/bin/openfpc-cx2db",
				"/usr/bin/openfpc-cx2db",
				"./openfpc-cx2db");
			unshift(@daemoncmds, $configs{$instance}{'CX2DB_CMD'})  if defined $configs{$instance}{'CX2DB_CMD'};
		}
		else {
			print "Unknown daemon $_\n";
			return(0);
		}
	}

	foreach (@daemoncmds) {
		if ( -x $_) {
			print " - $daemon is $_ \n" if $verbose;
			return($_);
		}
	}
	print " V Unable to find $daemon for $instance\n" if $verbose;
	foreach (@daemoncmds){
		print " - Tried : $_ \n" if $verbose;
	}
	return(0);				
}

=head2 openfpcqueued
	Start/Stop the OpenFPC Queue Daemon
	- Leon 2010	
=cut

sub openfpcqueued{
	my $action=shift;
	my $instance=shift;
	my $pidpath=$defaults{'PIDPATH'};
	my $daemoncmd=findcmd("openfpc-queued", $instance);	

	my $daemonargs="-c $conf_dir/$instance --daemon";

	$pidpath=$configs{$instance}{'PIDPATH'} if defined $configs{$instance}{'PIDPATH'};
	my $pidfile= $pidpath . "/" . "openfpc-queued-" . $configs{$instance}{'NODENAME'} . ".pid";

	# Get a PID, and check if it's running
	my $pid=getPidFromFile($pidfile);
	my $running=isPidRunning($pid) if ($pid);

	switch($action){
		case "start" {
			printf '%-70s', "Starting OpenFPC Queue Daemon ($configs{$instance}{'NODENAME'})... ";
			if ($running) {
				printf '%10s', "Running\n";
			} else {
				if ( -x $daemoncmd ) {
					my $result=system("$daemoncmd $daemonargs");
					if ($result) {
						printf '%10s', "Failed\n";
						print " - Check syslog for details\n" unless $quiet;
					} else {
						printf '%10s', "Done\n";
						return(1);
					}
				} else {
					printf '%10s', "Failed\n";
					print " - Cant find openfpc-queued. Check your conifg and OpenFPC install $daemoncmd!\n";
				}	
			}

		} 
		case "stop" {
			printf '%-70s', "Stopping OpenFPC Queue Daemon ($configs{$instance}{'NODENAME'})... ";
			if ($running) {
				my $result=system("kill $pid");
				if ($result) {
					printf '%10s', "Failed\n";
				} else {
					printf '%10s',"Done\n";
					return(1);
				}
			} else {
				printf '%10s',"Not running\n";
			}
		} 
		case "status" {
			printf '%-70s', "OpenFPC Queue Daemon  ($configs{$instance}{'NODENAME'}):"; 
			if ($running) {
				printf '%10s', "Running\n";
			} else {
				printf '%10s', "Stopped\n";
			}
		} 
	}
	return(0);
}


=head2 dameonlogger
	Start/Stop the OpenFPC Queue Daemon
	- Leon 2010	
=cut

sub openfpcdaemonlogger{
	my $action=shift;
	my $instance=shift;
	my $daemonargs="-d";
	
	my $daemoncmd=findcmd("openfpc-daemonlogger",$instance);

	my $pidpath=$defaults{'PIDPATH'};
	$pidpath=$configs{$instance}{'PIDPATH'} if defined $configs{$instance}{'PIDPATH'};

	my $pidfile="openfpc-daemonlogger-" . $configs{$instance}{'NODENAME'} . ".pid";
	# Check we have a BPF file before rtying to use it
	if ($configs{$instance}{'BPF_FILE'}) {
		print "Using BPF\n" if $verbose;
		if ( -f $configs{$instance}{'BPF_FILE'} ) {
			$daemonargs .= " -f $configs{$instance}{'BPF_FILE'} ";
			print "DEBUG: Found BPF file $configs{$instance}{'BPF_FILE'}" if $verbose;
		} else {
			print "WARNING: BPF file specified but does not exist! Starting without a BPF\n";
		}
	}
	$daemonargs .= 	"-i $configs{$instance}{'INTERFACE'} " .
			"-l $configs{$instance}{'BUFFER_PATH'} ".
			"-M $configs{$instance}{'PCAP_SPACE'} ".
			"-s $configs{$instance}{'FILE_SIZE'} ".
			"-p $pidfile " .
			"-P $pidpath " .
			"-n openfpc-$configs{$instance}{'NODENAME'}.pcap" .
			" >> /tmp/openfpc-dl-out 2>&1 ";
			# Daemonlogger is verbose at startup, and we need to store the op to find 
			# any problems if found. Throwing it to a file in /tmp works for now.

	# Get a PID, and check if it's runnings
	my $pid=getPidFromFile("$pidpath/$pidfile");
	my $running=isPidRunning($pid) if ($pid);

	switch($action){
		case "start" {
			#print "$daemoncmd $daemonargs\n";
			printf '%-70s',  "Starting Daemonlogger ($configs{$instance}{'NODENAME'})...";
			if ($running) {
				printf '%10s', "Running\n";
			} else {
				# Check if interface is available
				if (system("ifconfig $configs{$instance}{'INTERFACE'} up > /dev/null 2>&1")){
					print " - WARNING unable to bring $configs{$instance}{'INTERFACE'} up\n" unless $quiet;
				}
				# Check if BUFFER_PATH exists and is writable
				if ( ! -d  $configs{$instance}{'BUFFER_PATH'}){
					unless (mkpath($configs{$instance}{'BUFFER_PATH'})) { 
						printf '%10s',"Failed\n";	
						print " - Unable to create $configs{$instance}{'BUFFER_PATH'}\n" unless $quiet;
						return(0);
					}
				}
				if ( -x $daemoncmd ) {
					my $result=system("$daemoncmd $daemonargs");
					if ($result) {
						printf '%10s', "Failed\n";
					} else {
						printf '%10s', "Done\n";
						return(1);
					}
				} else {
					printf '%10s', "Failed\n";
					printf " - Dameonlogger not found on this system.\n" unless $quiet;
					return(0);
				}	
			}

		} 
		case "stop" {
			printf '%-70s',  "Stopping Daemonlogger... ";
			if ($running) {
				my $result=system("kill $pid");
				if ($result) {
					printf '%10s', "Failed\n";
				} else {
					printf '%10s', "Done\n";
					return(1);
				}
			} else {
				printf '%10s',"Not running\n";
			}
		} 
		case "status" {
			printf '%-70s', "Daemonlogger ($configs{$instance}{'NODENAME'}) :"; 
			if ($running) {
				printf '%10s', "Running\n";
			} else {
				printf '%10s', "Stopped\n";
			}
		} 
	}
	return(0);
}


sub openfpccxtracker{
	my $action=shift;
	my $instance=shift;
	my $pidpath=$defaults{'PIDPATH'};
	my $daemoncmd=findcmd("openfpc-cxtracker", $instance);
	my $sessiondir=$defaults{'SESSION_DIR'};
	my $pidfile="openfpc-cxtracker-$configs{$instance}{'NODENAME'}.pid";	
	$pidpath=$configs{$instance}{'PIDPATH'} if defined $configs{$instance}{'PIDPATH'};
	$sessiondir=$configs{$instance}{'SESSION_DIR'} if defined $configs{$instance}{'SESSION_DIR'};

	my $daemonargs="-i $configs{$instance}{'INTERFACE'} " .
			"-d $sessiondir " .
			"-p $pidfile " . 
			"-P $pidpath " .
			"-D > /tmp/openfpc-cxtracker-$configs{$instance}{'NODENAME'}";

	# Get a PID, and check if it's runnings
	my $pid=getPidFromFile("$pidpath/$pidfile");
	my $running=isPidRunning($pid) if ($pid);

	switch($action){
		case "start" {
			printf '%-70s', "Starting OpenFPC cxtracker ($configs{$instance}{'NODENAME'})... ";
			if ($running) {
				printf '%10s', "Running\n";
			} else {
				# Check if interface is available
				if (system("ifconfig $configs{$instance}{'INTERFACE'} up > /dev/null 2>&1")){
					print " - WARNING unable to bring $configs{$instance}{'INTERFACE'} up\n" unless $quiet;
				}
				# Check if BUFFER_PATH exists and is writable
				if ( ! -d  $configs{$instance}{'SESSION_DIR'}){
					unless (mkpath($configs{$instance}{'SESSION_DIR'})) { 
						printf '%10s',"Failed\n";	
						print " - Unable to create $configs{$instance}{'SESSION_DIR'}\n" unless $quiet;
						return(0);
					}
				}

				if ( -x $daemoncmd ) {
					my $result=system("$daemoncmd $daemonargs");
					if ($result) {
						printf '%10s', "Failed\n";
					} else {
						printf '%10s', "Done\n";
						return(1);
					}
				} else {
					printf '%10s', "Failed\n";
					print " - cxtracker not found on this system\n" unless $quiet;
				}	
			}

		} 
		case "stop" {
			printf '%-70s',  "Stopping OpenFPC cxtracker ($configs{$instance}{'NODENAME'})... ";
			if ($running) {
				my $result=system("kill $pid");
				if ($result) {
					printf '%10s', "Failed\n";
				} else {
					printf '%10s', "Done\n";
					return(1);
				}
			} else {
				printf '%10s',"Not running\n";
			}
		} 
		case "status" {
			printf '%-70s', "OpenFPC Connection Tracker ($configs{$instance}{'NODENAME'}) :"; 
			if ($running) {
				printf '%10s', "Running\n";
			} else {
				printf '%10s', "Stopped\n";
			}
		} 
	}
	return(0);
}

=head2 openfpccx2db
	Start/Stop cx2db (uploads sessions from disk to DB)
=cut

sub openfpccx2db{
	my $action=shift;
	my $instance=shift;
	my $pidpath=$defaults{'PIDPATH'};
	my $daemoncmd=findcmd("openfpc-cx2db", $instance);;
	my $pidfile="openfpc-cx2db-$configs{$instance}{'NODENAME'}.pid";	

	$pidpath=$configs{$instance}{'PIDPATH'} if defined $configs{$instance}{'PIDPATH'};

	my $daemonargs="--daemon --config $conf_dir/$instance " .
			"> /tmp/openfpc-cx2db-$configs{$instance}{'NODENAME'}.log";

	# Get a PID, and check if it's runnings
	my $pid=getPidFromFile("$pidpath/$pidfile");
	my $running=isPidRunning($pid) if ($pid);

	switch($action){
		case "start" {
			printf '%-70s', "Starting OpenFPC Connection Uploader ($configs{$instance}{'NODENAME'}) ... ";
			if ($running) {
				printf '%10s', "Running\n";
			} else {
				# Check if BUFFER_PATH exists and is writable
				if ( ! -d  $configs{$instance}{'SESSION_DIR'}){
					printf '%10s', "Failed. \n";	
					print " - Log path $configs{$instance}{'SESSION_DIR'} doesn't exist\n" unless $quiet;
					return(0);
				}
				if ( -x $daemoncmd ) {
					my $result=system("$daemoncmd $daemonargs");
					if ($result) {
						printf '%10s', "Failed\n";
					} else {
						printf '%10s', "Done\n";
						return(1);
					}
				} else {
					printf '%10s', "Failed\n";
					print " - openfpc-cx2db command not found on this system \n" unless $quiet;
				}	
			}

		} 
		case "stop" {
			printf '%-70s',  "Stopping OpenFPC Connection Uploader ($configs{$instance}{'NODENAME'})... ";
			if ($running) {
				my $result=system("kill $pid");
				if ($result) {
					printf '%10s', "Failed\n";
				} else {
					printf '%10s', "Done\n";
					return(1);
				}
			} else {
				printf '%10s',"Not running\n";
			}
		} 
		case "status" {
				printf '%-70s', "OpenFPC Connection Uploader ($configs{$instance}{'NODENAME'}) :"; 
			if ($running) {
				printf '%10s', "Running\n";
			} else {
				printf '%10s', "Stopped\n";
			}
		} 
	}
	return(0);
}



sub showhelp{

	print "
	openfpc : An OpenFPC control tool.

This tool start/stops all OpenFPC components on a host.  It does all the 
hard work so you don't have to.  Multiple instances of OpenFPC can exist 
on a host, this tool caters for that need allowing a user to start/stop 
either an instance, or all copies of a specific daemon.

e.g
To start all daemons required to operate an OpenFPC node with the name 
\"Default_Node\"

     openfpc --action start -t Default_Node  
     or
     openfpc --action start -t /etc/openfpc/openfpc-default.conf

To start all the instances of the openfpc-queued daemon
     openfpc --action start -t openfpc-queued

To get the status of all daemons that are configured to run on this host
    openfpc --action status

###############################################################################

openfpc <arguements>
	--action  or -a         start/stop/status
        --quiet   or -q         Quiet output for init scripts
        --thing   or -t         Take action on this \"thing\"

Note: --thing can be one of...
 - A Daemon name e.g.
   openfpc-daemonlogger
   openfpc-queued
   openfpc-cx2db
   openfpc-cxtracker
 - Config file e.g.
   openfpc-default.conf
 - Node name (defined in any config file in conf_dir) e.g.
   MyOpenFPCNode
   CORP.UK.DMZ.WWW

Part of the OpenFPC project http://www.openfpc.org
";
	exit 0;
}

GetOptions (    'a|action=s' => \$action,		# Action to take
		'v|verbose' => \$verbose,		# Verbose
		't|thing=s' => \$thing,			# The thing we want to take action on
		'q|quiet' => \$quiet,
		'help' => \$help,
);

&showhelp if ($help);
unless ($action) {
	print "No action specified. See --help\n";
	showhelp;	
}

# Check if we are root
unless ($> == 0 || $< == 0) { die "You need root privs to run this tool.\n" }

# Read in a hash of all configs on the system

opendir(my $dh, $conf_dir) || die("Unable to open config dir $conf_dir\n");
while(my $file=readdir $dh) {
	my $goodfile=0;
	# Check if this is an OpenFPC config file, or some other junk.
	open FILE, '<', "$conf_dir/$file" or die "Unable to open config file $conf_dir/$file $!";
	while(<FILE>) {
		chomp $_;
		$goodfile=1 if ( $_ =~ /^OFPC_ENABLED=/);
	}
	close(FILE);
	# Open file to read config if it is a valid OpenFPC config file
	if ($goodfile) {
		# Apply defaults to this instance file in case it's missing some of the required configuration lines.
		foreach (keys %defaults) {
			$configs{$file}{$_} = $defaults{$_};	
		}
		open FILE, '<', "$conf_dir/$file" or die "Unable to open config file $conf_dir/$file $!";
		while(my $line=<FILE>) {
        		chomp $line;
		        if ( $line =~ m/^[a-zA-Z]/) {
		                (my $key, my @value) = split /=/, $line;
		                unless ($key eq "USER") {
		                        $configs{$file}{$key} = join '=', @value;
	       	         	}    
	        	}
		}
		close(FILE);
		
		# Perform some sanity checks on the instance config, if something strange is found, disable it and warn the user.
		my $badconfig=0;
		if ($configs{$file}{NODENAME} =~ /[-\?\\\/]/ ) {
			print "ERROR: Invalid characters found in NODENAME in file $file \"$configs{$file}{NODENAME}\"\n";
			$badconfig=1;
		}
		if ($badconfig) {
			print "###############################################################################\n";
			$configs{$file}{OFPC_ENABLED}=0;
			print "WARNING: Bad configuration file $file. Disabling instance \"$configs{$file}{NODENAME}\"\n";
		}
		# Add this node if enabled to a list of all nodes on this system
		push(@nodes, $configs{$file}{NODENAME}) if ($configs{$file}{OFPC_ENABLED} =~ /[Yy]/ );
	}
}
closedir($dh);
# Make sure we have the minimum input to do something of use.

# Check we don't have any dupe nodes active.
while (my $node = shift(@nodes)){
	if (grep {$_ eq $node} @nodes) {
		die("ERROR: Duplicate node found enabled - $node. A Node name MUST be unique!\n");
	}
}

# Check if we need to act in the context of a daemon type, or an instance.
# Get the type of the thing the user wants to start/stop
if ($thing) {
	my $ofpc=getType($thing);
	#print "Filename is $ofpc->{'filename'} \nType is $ofpc->{'type'} \n" unless $quiet;

	if ( $ofpc->{'type'} eq "daemon" ) {
		my @instances=getInstanceByDaemon($thing);

		#foreach (@instances) {
		#	print "- $_\n";
		#}
		my $num=@instances;
		unless ($num) {
			print "WARNING: daemon $thing is not enabled in any instance\n" if $verbose;
		}
		switch($thing) {
			case "openfpc-queued" {
				foreach (@instances){
					openfpcqueued($action,$_);
				}
			}
			case "openfpc-daemonlogger" {
				foreach (@instances){
					openfpcdaemonlogger($action,$_);
				}
			}
			case "openfpc-cxtracker" {
				foreach (@instances){
					openfpccxtracker($action,$_);
				}
			}
			case "openfpc-cx2db" {
				foreach (@instances){
					openfpccx2db($action,$_);
				}
			}
			else {
				print " !  Unknown daemon $_\n";
			}
		}
	} elsif ( $ofpc->{'type'} eq "instance" ) {
		my $instance = $ofpc->{'filename'}; 		
		my @daemons=getDaemonsByInstance($ofpc->{'filename'});
		foreach (@daemons) {
			switch($_) {
				case "openfpc-queued" {
					openfpcqueued($action,$instance);
				}
				case "openfpc-daemonlogger" {
					openfpcdaemonlogger($action,$instance);
				}
				case "openfpc-cxtracker" {
					openfpccxtracker($action,$instance);
				}
				case "openfpc-cx2db" {
					openfpccx2db($action,$instance);
				}
				else {
					print " !  Unknown daemon $_\n";
				}
			}
		}
	} else {
		die("Sorry, I Don't know what \"$thing\" is.\nIt doesn't match any of the openfpc-daemon names, instance filenames, or Node names\n");
	}
} else {
	# Thing not speficied, taking action on 
	# all daemons for all instances.
	my $fail;
	foreach my $instance (keys(%configs)) {
		if (defined $configs{$instance}{'OFPC_ENABLED'}) {

			unless ($quiet) {
				print "###############################################################################\n";
				print "[*] OpenFPC instance $instance\n";
				print " -  NODENAME:              $configs{$instance}{'NODENAME'} \n" 	  if defined $configs{$instance}{'NODENAME'};
				print " -  DESCRIPTION:           $configs{$instance}{'DESCRIPTION'} \n"  if defined $configs{$instance}{'DESCRIPTION'};
				if ($configs{$instance}{'OFPC_ENABLED'} =~ /(y|1|yes)/i ) {
					print " -  STATUS :               ENABLED\n"; 
				} else {
					print " -  STATUS :               DISABLED\n"; 
				}
				print " -  PORT:                  $configs{$instance}{'OFPC_PORT'}\n"     if defined $configs{$instance}{'OFPC_PORT'};
				unless ( $configs{$instance}{'PROXY'} == 1 ) {
					print " -  INTERFACE:             $configs{$instance}{'INTERFACE'}\n" 	  if defined $configs{$instance}{'INTERFACE'};
					print " -  FULL PACKET CAPTURE:   ENABLED\n"	  if defined $configs{$instance}{'BUFFER_PATH'};
					print " -  PACKET STORE:          $configs{$instance}{'BUFFER_PATH'}\n"	  if defined $configs{$instance}{'BUFFER_PATH'};
       	                 		if ( defined $configs{$instance}{'ENABLE_SESSION'}) {
						if ($configs{$instance}{'ENABLE_SESSION'} == 1 ) {
							print " -  SESSION DATA SEARCH:   ENABLED\n" ;
							print " -  SESSION DATABASE NAME: $configs{$instance}{'SESSION_DB_NAME'}\n";
							# Get count of files in SESSION_DIR (these are waiting to be processed)
							# A high number here shows we have an problem with uploading to DB
							my $count=0;
							if (opendir(SESSION_DIR,$configs{$instance}{'SESSION_DIR'}) ) {
								while (my $filename=readdir(SESSION_DIR)) {
									$count++ unless $filename =~ /^(\.|failed)/;
								}
								print " -  SESSION LAG:           $count\n";
							}
						} else {
							print " -  SESSION DATA SEARCH:   DISABLED\n";	
						}
					} else {
						print " -  SESSION DATA SEARCH:   DISABLED\n";	
					}
				}
			}
			my @daemons=getDaemonsByInstance($instance);
			foreach (@daemons) {
				switch($_) {
					case "openfpc-queued" {
						openfpcqueued($action,$instance) or $fail=1;
					}
					case "openfpc-daemonlogger" {
						openfpcdaemonlogger($action,$instance) or $fail=1;
					}
					case "openfpc-cxtracker" {
						openfpccxtracker($action,$instance) or $fail=1;
					}
					case "openfpc-cx2db" {
						openfpccx2db($action,$instance) or $fail=1;
					}
					else {
						print "Unknown daemon $_\n";
						$fail=1;
					}
				}
			}
		}
	}
}
