#!/usr/bin/env php
<?php
//
// seed_throughput_db.php
//
// Seeds the check_throughput SQLite database with interface metadata discovered
// during wizard SNMP walks. Pre-populating the DB lets the first service check
// skip the expensive SNMP walk (label→ifIndex resolution) and jump straight to
// an snmpget — significantly reducing load on monitored devices.
//
// Seeded rows now include actual counter values and the current timestamp,
// so the first service check can compute throughput immediately.
//
// Called by the Network Switch/Router config wizard via sudo:
//   sudo /usr/bin/php /usr/local/nagiosxi/scripts/seed_throughput_db.php <base64_json>
//
// JSON structure (base64-encoded):
// {
//   "host": "192.168.1.1",
//   "interfaces": [
//     { "key": "eth0", "i_num": "5", "i_name": "eth0", "i_desc": "...", "i_alias": "...", "counter_bits": 64 },
//     ...
//   ]
// }
//

if (php_sapi_name() !== 'cli') {
    exit(1);
}

if ($argc < 2) {
    fwrite(STDERR, "Usage: seed_throughput_db.php <base64_json>\n");
    exit(1);
}

$json = base64_decode($argv[1], true);
if ($json === false) {
    fwrite(STDERR, "Invalid base64 input\n");
    exit(1);
}

$data = json_decode($json, true);
if (!is_array($data) || empty($data['host']) || !is_array($data['interfaces'] ?? null)) {
    fwrite(STDERR, "Invalid JSON structure\n");
    exit(1);
}

$host = $data['host'];
$interfaces = $data['interfaces'];

if (empty($interfaces)) {
    exit(0);
}

// Determine DB path (mirrors check_throughput.c determine_db_path)
$db_name = 'nagios_snmp_throughput.db';
$candidate_dirs = ['/usr/local/nagios/var', '/var/tmp'];
$db_path = null;

foreach ($candidate_dirs as $dir) {
    if (!is_dir($dir)) {
        @mkdir($dir, 0755, true);
    }
    if (is_writable($dir) || is_writable($dir . '/' . $db_name)) {
        $db_path = $dir . '/' . $db_name;
        break;
    }
}

if ($db_path === null) {
    fwrite(STDERR, "No writable directory for database\n");
    exit(1);
}

// Sanitize host into a SQLite table name (mirrors check_throughput.c sanitize_host_for_table)
function sanitize_host_for_table($host) {
    $result = 'host_';
    for ($i = 0; $i < strlen($host); $i++) {
        $c = $host[$i];
        if ($c === '.') {
            $result .= '_';
        } else if (ctype_alnum($c) || $c === '_') {
            $result .= $c;
        } else {
            $result .= '_';
        }
    }
    return $result;
}

$table = sanitize_host_for_table($host);

// Table name is safe — only [a-zA-Z0-9_] from sanitize_host_for_table
$quoted_table = '"' . $table . '"';

try {
    $prev_umask = umask(0133);
    $db = new SQLite3($db_path);
    umask($prev_umask);
    $db->busyTimeout(5000);

    // Use WAL journal mode so readers are never blocked by concurrent writes. Required on older SQLite builds
    $db->exec('PRAGMA journal_mode=WAL');

    // Create table if it doesn't exist (same schema as check_throughput.c db_init)
    $db->exec("CREATE TABLE IF NOT EXISTS $quoted_table (
        interface TEXT NOT NULL PRIMARY KEY,
        i_num TEXT,
        i_name TEXT,
        i_desc TEXT,
        i_alias TEXT,
        timestamp INTEGER NOT NULL,
        in_octets INTEGER NOT NULL,
        out_octets INTEGER NOT NULL,
        counter_bits INTEGER NOT NULL
    )");

    // INSERT OR IGNORE: don't overwrite existing rows from real check_throughput runs
    $stmt = $db->prepare("INSERT OR IGNORE INTO $quoted_table
        (interface, i_num, i_name, i_desc, i_alias, timestamp, in_octets, out_octets, counter_bits)
        VALUES (:key, :i_num, :i_name, :i_desc, :i_alias, :timestamp, :in_octets, :out_octets, :counter_bits)");

    $seeded = 0;
    foreach ($interfaces as $iface) {
        if (!isset($iface['key']) || $iface['key'] === '' || empty($iface['counter_bits'])) {
            continue;
        }
        $stmt->bindValue(':key', (string)$iface['key'], SQLITE3_TEXT);
        $stmt->bindValue(':i_num', (string)($iface['i_num'] ?? ''), SQLITE3_TEXT);
        $stmt->bindValue(':i_name', (string)($iface['i_name'] ?? ''), SQLITE3_TEXT);
        $stmt->bindValue(':i_desc', (string)($iface['i_desc'] ?? ''), SQLITE3_TEXT);
        $stmt->bindValue(':i_alias', (string)($iface['i_alias'] ?? ''), SQLITE3_TEXT);
        $stmt->bindValue(':timestamp', 0, SQLITE3_INTEGER);
        $stmt->bindValue(':in_octets', (int)($iface['in_octets'] ?? 0), SQLITE3_INTEGER);
        $stmt->bindValue(':out_octets', (int)($iface['out_octets'] ?? 0), SQLITE3_INTEGER);
        $stmt->bindValue(':counter_bits', (int)$iface['counter_bits'], SQLITE3_INTEGER);
        $stmt->execute();
        $stmt->reset();
        $seeded++;
    }

    $db->close();

    // Fix ownership — this script runs as root via sudo; the DB must be
    // owned by nagios so that check_throughput (running as nagios) can write.
    $nagios_user = 'nagios';
    $nagios_group = 'nagios';
    $xi_sys_cfg = '/usr/local/nagiosxi/var/xi-sys.cfg';
    if (file_exists($xi_sys_cfg)) {
        $cfg_content = file_get_contents($xi_sys_cfg);
        if (preg_match('/^nagiosuser=(.+)$/m', $cfg_content, $m)) {
            $nagios_user = trim($m[1], " \t\n\r\0\x0B'\"");
        }
        if (preg_match('/^nagiosgroup=(.+)$/m', $cfg_content, $m)) {
            $nagios_group = trim($m[1], " \t\n\r\0\x0B'\"");
        }
    }

    $db_files = [$db_path, $db_path . '-wal', $db_path . '-shm'];
    foreach ($db_files as $f) {
        if (!file_exists($f)) {
            continue;
        }
        if (!chown($f, $nagios_user) || !chgrp($f, $nagios_group) || !chmod($f, 0644)) {
            fwrite(STDERR, "Warning: could not set ownership/permissions on $f — "
                         . "check_throughput may not be able to write the database.\n"
                         . "Fix manually: chown {$nagios_user}:{$nagios_group} $f && chmod 0644 $f\n");
        }
    }

    fwrite(STDOUT, "Seeded $seeded interface(s) for host $host\n");

} catch (Exception $e) {
    fwrite(STDERR, "Database error: " . $e->getMessage() . "\n");
    exit(1);
}

exit(0);
