168 lines
5.3 KiB
PHP
Executable File
168 lines
5.3 KiB
PHP
Executable File
#!/usr/bin/env php
|
|
<?php
|
|
/**
|
|
* Monitoring Update Engine - PHP Version
|
|
* Copyright (C) 2026 Cédric Abonnel
|
|
*/
|
|
|
|
require_once __DIR__ . '/../lib/monitoring-lib.php';
|
|
|
|
// --- Configuration ---
|
|
// Note : La lib a déjà chargé $CONFIG['UPDATE_BASE_URL'] etc. depuis monitoring.local.conf.php
|
|
// On ne charge les fichiers spécifiques que s'ils apportent des règles de mise à jour uniques.
|
|
foreach (["/opt/monitoring/conf/autoupdate.conf.php", "/opt/monitoring/conf/autoupdate.local.conf.php"] as $conf) {
|
|
if (file_exists($conf)) {
|
|
$extra_conf = include $conf;
|
|
if (is_array($extra_conf)) {
|
|
$CONFIG = array_replace_recursive($CONFIG, $extra_conf);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Variables par défaut (fallback si absent de la config globale)
|
|
$UPDATE_ENABLED = $CONFIG['UPDATE_ENABLED'] ?? true;
|
|
$UPDATE_TMP_DIR = $CONFIG['UPDATE_TMP_DIR'] ?? '/tmp/monitoring-update';
|
|
$UPDATE_TIMEOUT_TOTAL = $CONFIG['UPDATE_TIMEOUT_TOTAL'] ?? 15;
|
|
$UPDATE_MANIFEST_URL = $CONFIG['UPDATE_MANIFEST_URL'] ?? '';
|
|
$UPDATE_BASE_URL = $CONFIG['UPDATE_BASE_URL'] ?? '';
|
|
$UPDATE_ALLOW_DELETE = $CONFIG['UPDATE_ALLOW_DELETE'] ?? false;
|
|
$MONITORING_BASE_DIR = $MONITORING_BASE_DIR; // Provient de la lib
|
|
|
|
// --- Initialisation ---
|
|
lock_or_exit("monitoring-update");
|
|
|
|
if (!$UPDATE_ENABLED) {
|
|
log_notice("update_disabled", "Mise à jour désactivée");
|
|
exit(0);
|
|
}
|
|
|
|
if (!is_dir($UPDATE_TMP_DIR)) {
|
|
mkdir($UPDATE_TMP_DIR, 0755, true);
|
|
}
|
|
|
|
/**
|
|
* Télécharge et valide le manifeste
|
|
*/
|
|
function fetch_manifest($url) {
|
|
global $UPDATE_TIMEOUT_TOTAL;
|
|
|
|
$ch = curl_init($url);
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_TIMEOUT => $UPDATE_TIMEOUT_TOTAL,
|
|
CURLOPT_FAILONERROR => true,
|
|
CURLOPT_FOLLOWLOCATION => true
|
|
]);
|
|
|
|
$content = curl_exec($ch);
|
|
if (curl_errno($ch)) {
|
|
log_error("manifest_download_failed", "Échec téléchargement manifeste", ["url" => $url, "err" => curl_error($ch)]);
|
|
return false;
|
|
}
|
|
curl_close($ch);
|
|
|
|
$manifest_entries = [];
|
|
$lines = explode("\n", trim($content));
|
|
|
|
foreach ($lines as $line) {
|
|
if (preg_match('/^([0-9a-fA-F]{64})\s+(644|755)\s+((bin|lib|conf)\/[A-Za-z0-9._\/-]+)$/', trim($line), $matches)) {
|
|
$manifest_entries[] = ['hash' => $matches[1], 'mode' => $matches[2], 'path' => $matches[3]];
|
|
}
|
|
}
|
|
return $manifest_entries;
|
|
}
|
|
|
|
/**
|
|
* Met à jour un fichier
|
|
*/
|
|
function update_one_file($entry) {
|
|
global $MONITORING_BASE_DIR, $UPDATE_BASE_URL, $UPDATE_TMP_DIR, $UPDATE_TIMEOUT_TOTAL;
|
|
|
|
$rel_path = $entry['path'];
|
|
$target_file = $MONITORING_BASE_DIR . '/' . $rel_path;
|
|
$remote_url = rtrim($UPDATE_BASE_URL, '/') . '/' . $rel_path;
|
|
$expected_hash = strtolower($entry['hash']);
|
|
|
|
if (file_exists($target_file) && hash_file('sha256', $target_file) === $expected_hash) {
|
|
return true;
|
|
}
|
|
|
|
$tmp_file = $UPDATE_TMP_DIR . '/' . basename($rel_path) . '.' . uniqid();
|
|
$ch = curl_init($remote_url);
|
|
$fp = fopen($tmp_file, 'wb');
|
|
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_FILE => $fp,
|
|
CURLOPT_TIMEOUT => $UPDATE_TIMEOUT_TOTAL,
|
|
CURLOPT_FAILONERROR => true,
|
|
CURLOPT_FOLLOWLOCATION => true
|
|
]);
|
|
|
|
$success = curl_exec($ch);
|
|
curl_close($ch);
|
|
fclose($fp);
|
|
|
|
if (!$success || hash_file('sha256', $tmp_file) !== $expected_hash) {
|
|
log_error("update_failed", "Fichier invalide ou corrompu", ["file" => $rel_path]);
|
|
@unlink($tmp_file);
|
|
return false;
|
|
}
|
|
|
|
ensure_parent_dir($target_file);
|
|
chmod($tmp_file, octdec($entry['mode']));
|
|
safe_mv($tmp_file, $target_file); // Utilise la fonction safe_mv de ta lib
|
|
|
|
log_notice("file_updated", "Mise à jour appliquée", ["file" => $rel_path]);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Nettoyage
|
|
*/
|
|
function delete_extra_files($remote_files) {
|
|
global $UPDATE_ALLOW_DELETE, $MONITORING_BASE_DIR, $SCRIPT_PATH;
|
|
if (!$UPDATE_ALLOW_DELETE) return;
|
|
|
|
foreach (['bin', 'lib', 'conf'] as $dir) {
|
|
$full_path = $MONITORING_BASE_DIR . '/' . $dir;
|
|
if (!is_dir($full_path)) continue;
|
|
|
|
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($full_path, RecursiveDirectoryIterator::SKIP_DOTS));
|
|
|
|
foreach ($iterator as $file) {
|
|
$path = $file->getPathname();
|
|
$rel_path = substr($path, strlen($MONITORING_BASE_DIR) + 1);
|
|
|
|
// PROTECTIONS
|
|
if (in_array($rel_path, $remote_files)) continue;
|
|
if (str_contains($rel_path, '.local.')) continue; // Protection fichiers locaux
|
|
if ($path === $SCRIPT_PATH) continue; // Ne pas se suicider
|
|
|
|
if (@unlink($path)) {
|
|
log_notice("file_deleted", "Fichier obsolète supprimé", ["file" => $rel_path]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Main ---
|
|
$manifest = fetch_manifest($UPDATE_MANIFEST_URL);
|
|
if (!$manifest) exit(2);
|
|
|
|
$remote_paths = [];
|
|
$updated = 0; $failed = 0;
|
|
|
|
foreach ($manifest as $entry) {
|
|
$remote_paths[] = $entry['path'];
|
|
update_one_file($entry) ? $updated++ : $failed++;
|
|
}
|
|
|
|
delete_extra_files($remote_paths);
|
|
|
|
if ($failed > 0) {
|
|
log_warning("update_partial", "Mise à jour terminée avec erreurs", ["failed" => $failed]);
|
|
} else {
|
|
log_info("update_ok", "Mise à jour terminée avec succès");
|
|
}
|
|
|
|
exit_with_status(); |