#!/usr/bin/php
<?php
/**
 * ```
 *                      ____  _     ____
 *  _ __ ___  _ __ ___ |  _ \| |__ |  _ \  __ _  ___ _ __ ___   ___  _ __
 * | '_ ` _ \| '_ ` _ \| | | | '_ \| | | |/ _` |/ _ \ '_ ` _ \ / _ \| '_ \
 * | | | | | | | | | | | |_| | |_) | |_| | (_| |  __/ | | | | | (_) | | | |
 * |_| |_| |_|_| |_| |_|____/|_.__/|____/ \__,_|\___|_| |_| |_|\___/|_| |_|
 * ```
 *
 * mmDbDaemon - Memory-resident MaxMind Database reader implementation in PHP
 *
 * @copyright Noumenia (C) 2023 - All rights reserved - Software Development - www.noumenia.gr
 * @license GNU GPL v3.0
 * @package mmDbDaemon
 * @subpackage cli
 */

// Cli execution only
if(php_sapi_name() !== "cli") {

	echo "[ERROR] This script can only be executed under a PHP shell cli.\n";
	exit(9);

}

// Parse command line parameters
$cmdParameters = getopt(

	// Short
	"Vhvu:g:p:l:c:a:m:",

	// Long
	array(
		"version",
		"help",
		"verbose",
		"user:",
		"group:",
		"pid:",
		"processlimit:",
		"connection:",
		"timeout:",
		"autoload:",
		"mmdb:"
	)

);
if($cmdParameters === false)
	$cmdParameters = array();

// Handle invalid parameters
foreach($cmdParameters as &$value) {

	// Convert arrays of multiple parameters of the same name into a single string
	if(is_array($value))
		$value = array_pop($value);

	if(!is_string($value))
		$value = "";

}
/** @var array<string, string> $cmdParameters */

// Clean-up
unset($value);

// Composer or RPM packages
if(is_file(__DIR__ . "/vendor/autoload.php")) {

	require_once(__DIR__ . "/vendor/autoload.php");

} else {

	// Autoload libLoggerPHP
	require_once("/usr/share/php/libLoggerPHP/controller/common.inc.php");

	// Autoload libSDManagerPHP
	require_once("/usr/share/php/libSDManagerPHP/controller/common.inc.php");

}

// Load common library objects and default configuration parameters
if(is_file(__DIR__ . "/controller/common.inc.php")) {

	require_once(__DIR__ . "/controller/common.inc.php");

} elseif(is_file("/usr/share/php/mmDbDaemon/controller/common.inc.php")) {

	require_once("/usr/share/php/mmDbDaemon/controller/common.inc.php");

} else {

	$error = "[mmDbDaemon: ERROR - Failed to load the common autoloader: mmDbDaemon/controller/common.inc.php]";
	syslog(LOG_ERR, $error);
	echo $error . "\n";
	exit(9);

}

// Parse parameters
if(
	isset($cmdParameters['V']) ||
	isset($cmdParameters['version']) ||
	isset($cmdParameters['h']) ||
	isset($cmdParameters['help'])
) {

	if(is_file(__DIR__."/controller/help.inc.php")) {

		include __DIR__."/controller/help.inc.php";

	} elseif(is_file("/usr/share/php/mmDbDaemon/controller/help.inc.php")) {

		include "/usr/share/php/mmDbDaemon/controller/help.inc.php";

	} else {

		$error = "[mmDbDaemon: ERROR - Failed to load the help file: mmDbDaemon/controller/help.inc.php]";
		syslog(LOG_ERR, $error);
		echo $error . "\n";
		exit(9);

	}

}

// Daemon user
if(isset($cmdParameters['u']))
	$daemonUser = $cmdParameters['u'];
elseif(isset($cmdParameters['user']))
	$daemonUser = $cmdParameters['user'];
else {

	// Current user
	$cUser = posix_getpwuid(posix_getuid());
	if($cUser === false) {

		\libLoggerPHP\Log::error("[mmDbDaemon: ERROR - Failed to get information about the current user ownership.]");
		exit(9);

	}

	$daemonUser = $cUser['name'];

	// Clean-up
	unset($cUser);

}

// Daemon group
if(isset($cmdParameters['g']))
	$daemonGroup = $cmdParameters['g'];
elseif(isset($cmdParameters['group']))
	$daemonGroup = $cmdParameters['group'];
else {

	// Current group
	$cGroup = posix_getgrgid(posix_getgid());
	if($cGroup === false) {

		\libLoggerPHP\Log::error("[mmDbDaemon: ERROR - Failed to get information about the current group ownership.]");
		exit(9);

	}

	$daemonGroup = $cGroup['name'];

	// Clean-up
	unset($cGroup);

}

// PID file
if(isset($cmdParameters['p']))
	$filePid = $cmdParameters['p'];
elseif(isset($cmdParameters['pid']))
	$filePid = $cmdParameters['pid'];
else
	$filePid = "/run/mmDbDaemon/mmDbDaemon.pid";

// Process limit
if(isset($cmdParameters['l']))
	$processLimit = intval($cmdParameters['l']);
elseif(isset($cmdParameters['processlimit']))
	$processLimit = intval($cmdParameters['processlimit']);
else
	$processLimit = 1024;

// Connection
if(isset($cmdParameters['c']))
	$connection = $cmdParameters['c'];
elseif(isset($cmdParameters['connection']))
	$connection = $cmdParameters['connection'];
else
	$connection = "unix:/run/mmDbDaemon/mmDbDaemon.sock";

// Socket timeout
if(isset($cmdParameters['t']))
	$timeout = intval($cmdParameters['t']);
elseif(isset($cmdParameters['timeout']))
	$timeout = intval($cmdParameters['timeout']);
else
	$timeout = 10;

// Autoload
if(isset($cmdParameters['a']))
	$autoload = $cmdParameters['a'];
elseif(isset($cmdParameters['autoload']))
	$autoload = $cmdParameters['autoload'];
elseif(is_file(__DIR__ . "/vendor/autoload.php"))
	$autoload = __DIR__ . "/vendor/autoload.php";
elseif(is_file(__DIR__ . "/vendor/maxmind-db/reader/autoload.php"))
	$autoload = __DIR__ . "/vendor/maxmind-db/reader/autoload.php";
else
	$autoload = "/usr/share/php/MaxMind/Db/Reader/autoload.php";

// File check
if(!is_file($autoload)) {

	\libLoggerPHP\Log::error("[mmDbDaemon: ERROR - Failed to read MaxMind DB Reader PHP autoload.php file: " . $autoload . "]");
	exit(9);

}

// Load required library
require_once($autoload);

// Clean-up
unset($autoload);

// MMDB
if(isset($cmdParameters['m']))
	$mmdb = $cmdParameters['m'];
elseif(isset($cmdParameters['mmdb']))
	$mmdb = $cmdParameters['mmdb'];
else
	$mmdb = "/usr/share/GeoIP/GeoLite2-City.mmdb";

// MMDB file check
if(!is_file($mmdb)) {

	\libLoggerPHP\Log::error("[mmDbDaemon: ERROR - Failed to read MMDB file: " . $mmdb . "]");
	exit(9);

}

// Change current directory to the same location as the file PID
if(!empty($filePid)) {

	// Extract the directory only
	$dirPid = dirname($filePid);

	// Validate that it exists
	if(!is_dir($dirPid)) {

		// Create PID directory
		$rc = @mkdir($dirPid, 0755);
		if($rc === false) {

			\libLoggerPHP\Log::error("[mmDbDaemon: ERROR - PID directory error, could not create the PID directory]");
			exit(9);

		}

		$rc = chown($dirPid, $daemonUser);
		if($rc === false) {

			\libLoggerPHP\Log::error("[mmDbDaemon: ERROR - PID directory error, could not set the user owner]");
			exit(9);

		}

		$rc = chgrp($dirPid, $daemonGroup);
		if($rc === false) {

			\libLoggerPHP\Log::error("[mmDbDaemon: ERROR - PID directory error, could not set the group owner]");
			exit(9);

		}

	}

	// Change to the PID directory
	$rc = chdir($dirPid);
	if($rc === false) {

		\libLoggerPHP\Log::error("[mmDbDaemon: ERROR - Failed to change to the PID directory: " . $dirPid . "]");
		exit(9);

	}

	// Clean-up
	unset($dirPid);

}

try {

	// Create daemon object
	$daemon = new Daemon(
		$daemonUser,
		$daemonGroup,
		$filePid,
		$processLimit,
		$connection,
		$timeout,
		array(),
		$mmdb
	);

} catch(Exception $e) {

	\libLoggerPHP\Log::error("[mmDbDaemon: EXCEPTION " . $e->getMessage() . "]");
	exit(9);

}

// Accept connections
$daemon->acceptConnections();

