#!/bin/php
<?php

$rwaccess=false;
if(isset($argv[1]) && $argv[1]=="fastfetch_output"){
    echo "skip locking, because we are in fastfetch_output\r\n";
}
elseif(!file_exists("/var/run/update_status.lock")){
    $rwaccess = @touch("/var/run/update_status.lock");
}
else{
    $rwaccess=true;
}
if($rwaccess) {
    echo "Claim flock... ";
    $fp_lock = fopen("/var/run/update_status.lock", "r");
    flock($fp_lock, LOCK_EX);
    echo "done\r\n";
}
else{
    echo "Not claiming lock - r/o-mode\r\n";
}

if(!isset($argv[1])){
    print_usage();
}
elseif($argv[1]=="update_cache_only"){
    if(!$rwaccess){
        echo "this is only possible in rw-access mode.\r\n";
        exit(1);
    }
    $fetch = fetch_data();
    $serial = serialize($fetch);
    file_put_contents("/var/cache/update-status.db",$serial);
    echo "done!\r\n";
    exit(0);
}
elseif($argv[1]=="read_cache"){
    if(!file_exists("/var/cache/update-status.db")){
	echo "error: update-status-db not exists :(\r\n";
	exit(1);
    }
    $fetch = unserialize(file_get_contents("/var/cache/update-status.db"));
    print_long($fetch);
    exit(0);
}
elseif($argv[1]=="force_update"){
    if(!$rwaccess){
        echo "this is only possible in rw-access mode.\r\n";
        exit(1);
    }
    $fetch = fetch_data();
    $serial = serialize($fetch);
    file_put_contents("/var/cache/update-status.db",$serial);
    print_long($fetch);
    exit(0);
}
elseif($argv[1]=="fastfetch_output"){
    if(isset($argv[2]) && $argv[2]=="update"){
        if(!$rwaccess){
            echo "this is only possible in rw-access mode.\r\n";
            exit(1);
        }
        $fetch = fetch_data();
        $serial = serialize($fetch);
        file_put_contents("/var/cache/update-status.db",$serial);
    }
    else{
	if(!file_exists("/var/cache/update-status.db")){
	    echo "error: update-status-db not exists :(\r\n";
	    exit(1);
	}
	$fetch = unserialize(file_get_contents("/var/cache/update-status.db"));
    }
    print_short($fetch);
    exit(0);
}
else{
    print_usage();
}
if(!$rwaccess){
    fclose($fp_lock);
}

function print_usage(){
    global $argv;
    echo "Usage: ".$argv[0]." update_cache_only|read_cache|force_update|fastfetch_output\r\n";
    echo " -update_cache_only: intendet for updating cache only as repeated cronjob\r\n";
    echo " -read_cache: read contents from last cached entry\r\n";
    echo " -force_update: update cache and return values\r\n";
    echo " -fastfetch_output [update]: output data for fastfetch usage\r\n";
    exit(0);
}


function print_short($fetch){
    $restarts = $fetch["needrestart_phpsvc"]+$fetch["needrestart_app_svc"]+$fetch["needrestart_runneedrestart_svc"]+$fetch["needrestart_rc_svc"]+$fetch["needrestart_app_kernel"]+$fetch["needrestart_app_ucode"]+$fetch["needrestart_runneedrestart_sys"];
    if($fetch["outdated_user_sessions"]){
        $restarts++;
    }
    echo "Time: ".date("d.m.Y H:i:s T",$fetch["time"])."\r\n";
    echo "Revisions: ".$fetch["currev_no"]." -> ".$fetch["target_rev_no"]." (".$fetch["target_rev_age"]."/".(round((time()-$fetch["currev_dt_int"])/24/60/60,0))." days old) - top ".$fetch["target_rev_pilot"]."\r\n";
    echo "Packages: ".$fetch["packages"]." / ".$fetch["compile"]." / ".$fetch["download"]."\r\n";
    echo "Configs: ".count($fetch["config_outstanding"])."\r\n";
    echo "Restart necessary: ".($restarts>0?"YES":"no")."\r\n";

    if(
        !isset($fetch["perm_last_fully_updated_rev"]) ||
        !isset($fetch["perm_last_fully_updated_dt"]) ||
        !isset($fetch["perm_last_fully_updated_rebooted_rev"]) ||
        !isset($fetch["perm_last_fully_updated_rebooted_dt"])
    ){

        echo "LastFinalizedUpdateCompleted: no informations (cache from old version?)\r\n";
        echo "LastFinalizedUpdateCompletedAndRebooted: no informations (cache from old version?)\r\n";
    }
    else {
        if(empty($fetch["perm_last_fully_updated_dt"]) || empty($fetch["perm_last_fully_updated_rev"])){
            echo "LastFinalizedUpdateCompletedWOReboot: NEVER\r\n";
        }
        else{
            echo "LastFinalizedUpdateCompletedWOReboot: rev" . $fetch["perm_last_fully_updated_rev"] . " - " . (round((time() - $fetch["perm_last_fully_updated_dt"]) / 24 / 60 / 60, 0)) . " days old\r\n";
        }
        if(empty($fetch["perm_last_fully_updated_rebooted_dt"]) || empty($fetch["perm_last_fully_updated_rebooted_rev"])){
            echo "LastFinalizedUpdateCompletedAndRebooted: NEVER\r\n";
        }
        else{
            echo "LastFinalizedUpdateCompletedAndRebooted: rev" . $fetch["perm_last_fully_updated_rebooted_rev"] . " - " . (round((time() - $fetch["perm_last_fully_updated_rebooted_dt"]) / 24 / 60 / 60, 0)) . " days old\r\n";
        }
    }
    exit(0);
}

function print_long($fetch){
    echo "Status from: ".date("d.m.Y H:i:s T",$fetch["time"])."\r\n";
    echo "TargetRev: ".$fetch["target_rev_no"]."\r\n";
    echo "TargetRevAge: ".$fetch["target_rev_age"]." days\r\n";
    echo "TargetRevPilotGroup: ".$fetch["target_rev_pilot"]."\r\n";

    echo "CurrentRev: ".$fetch["currev_no"]."\r\n";
    echo "CurrentRevAge: ".(round((time()-$fetch["currev_dt_int"])/24/60/60,0))." days (".$fetch["currev_dt_str"].")\r\n";

    echo "PackageUpdatesPending: ".$fetch["packages"]."\r\n";
    echo "CompilingsPending: ".$fetch["compile"]."\r\n";
    echo "DownloadsPending: ".$fetch["download"]."\r\n";

    echo "ServiceRebootPending(needrestart_phpsvc OLD! included in needrestart line!): ".$fetch["needrestart_phpsvc"]." ".($fetch["needrestart_phpsvc"]>0?"(".join(",",$fetch["needrestart_phpsvc_details"]).")":"")."\r\n";
    echo "ServiceRebootPending(needrestart): ".$fetch["needrestart_app_svc"]." ".($fetch["needrestart_app_svc"]>0?"(".join(",",$fetch["needrestart_app_svc_details"]).")":"")."\r\n";
    echo "ServiceRebootPending(/run/needrestart/service): ".$fetch["needrestart_runneedrestart_svc"]." ".($fetch["needrestart_runneedrestart_svc"]>0?"(".join(",",$fetch["needrestart_runneedrestart_svc_details"]).")":"")."\r\n";
    if(in_array("dbus",$fetch["needrestart_runneedrestart_svc_details"])){
        echo "CAUTION: restarting dbus causes desktop-session to be killed if used!\r\n";
    }
    echo "ServiceRebootPending(rc-status): ".$fetch["needrestart_rc_svc"]." ".($fetch["needrestart_rc_svc"]>0?"(".join(",",$fetch["needrestart_rc_svc_details"]).")":"")."\r\n";
    echo "SystemRebootPending(needrestart/kernel): ".$fetch["needrestart_app_kernel"]."\r\n";
    echo "SystemRebootPending(needrestart/ucode): ".$fetch["needrestart_app_ucode"]."\r\n";
    if($fetch["outdated_user_sessions"]){
        echo "UserSessionOutdated: Yes\r\n";
    }
    else{
        echo "UserSessionOutdated: No\r\n";
    }
    echo "SystemRebootPending(/run/needrestart/system): ".$fetch["needrestart_runneedrestart_sys"]." ".($fetch["needrestart_runneedrestart_sys"]>0?"(".join(",",$fetch["needrestart_runneedrestart_sys_details"]).")":"")."\r\n";
    echo "ConfigUpdatePending: ".count($fetch["config_outstanding"])." ".(count($fetch["config_outstanding"])>0?"(".join(",",$fetch["config_outstanding"]).")":"")."\r\n";


    if(
        !isset($fetch["perm_last_fully_updated_rev"]) ||
        !isset($fetch["perm_last_fully_updated_dt"]) ||
        !isset($fetch["perm_last_fully_updated_rebooted_rev"]) ||
        !isset($fetch["perm_last_fully_updated_rebooted_dt"]) ||
        !isset($fetch["perm_last_fully_updated_configged_rev"]) ||
        !isset($fetch["perm_last_fully_updated_configged_dt"])
    ){

        echo "LastFinalizedUpdateCompleted: no informations (cache from old version?)\r\n";
        echo "LastFinalizedUpdateCompletedAndRebooted: no informations (cache from old version?)\r\n";
        echo "LastFinalizedUpdateCompletedAndConfigged: no informations (cache from old version?)\r\n";
    }
    else {
        if(empty($fetch["perm_last_fully_updated_dt"]) || empty($fetch["perm_last_fully_updated_rev"])){
            echo "LastFinalizedUpdateCompleted: NEVER\r\n";
        }
        else{
            echo "LastFinalizedUpdateCompleted: " . date("d.m.Y H:i:s T", $fetch["perm_last_fully_updated_dt"]) . "(rev: " . $fetch["perm_last_fully_updated_rev"] . ", age: " . (round((time() - $fetch["perm_last_fully_updated_dt"]) / 24 / 60 / 60, 0)) . " days)\r\n";
        }
        if(empty($fetch["perm_last_fully_updated_rebooted_dt"]) || empty($fetch["perm_last_fully_updated_rebooted_rev"])){
            echo "LastFinalizedUpdateCompletedAndRebooted: NEVER\r\n";
        }
        else{
            echo "LastFinalizedUpdateCompletedAndRebooted: " . date("d.m.Y H:i:s T", $fetch["perm_last_fully_updated_rebooted_dt"]) . "(rev: " . $fetch["perm_last_fully_updated_rebooted_rev"] . ", age: " . (round((time() - $fetch["perm_last_fully_updated_rebooted_dt"]) / 24 / 60 / 60, 0)) . " days)\r\n";
        }
        if(empty($fetch["perm_last_fully_updated_configged_dt"]) || empty($fetch["perm_last_fully_updated_configged_rev"])){
            echo "LastFinalizedUpdateCompletedAndConfigged: NEVER\r\n";
        }
        else{
            echo "LastFinalizedUpdateCompletedAndConfigged: " . date("d.m.Y H:i:s T", $fetch["perm_last_fully_updated_configged_dt"]) . "(rev: " . $fetch["perm_last_fully_updated_configged_rev"] . ", age: " . (round((time() - $fetch["perm_last_fully_updated_configged_dt"]) / 24 / 60 / 60, 0)) . " days)\r\n";
        }
    }
    exit(0);
}

function fetch_data(){
    $permanent_data=load_permanent_infos_from_cache();

    $fetch=array();
    $cmd1 = shell_exec("emerge --update --deep --newuse --rebuilt-binaries --autounmask-backtrack=y -pv world 2>&1");
    $cmd2 = shell_exec("update_getmytargetrev.php");
    $cmd3 = shell_exec("emerge --info");
    $cmd4 = shell_exec("needrestart_phpsvc");
    $cmd5 = shell_exec("needrestart -m a -r l -b 2>&1");
    $cmd7 = shell_exec("rc-status --all");


    // Search for count packages
    $temp = explode("\nTotal: ",$cmd1);
    $temp = explode(" package",$temp[1]);
    $fetch["packages"]=trim($temp[0]);

    // Search for download size
    $temp = explode("Size of downloads: ",$cmd1);
    $temp = explode("\n",$temp[1]);
    $fetch["download"]=trim($temp[0]);

    // Search for compile
    $temp = substr_count($cmd1,"\n[ebuild");
    $fetch["compile"]=$temp;

    // Search for target rev no
    $temp = explode("Target Revision is: ",$cmd2);
    $temp = explode("\n",$temp[1]);
    $fetch["target_rev_no"]=trim($temp[0]);

    // Search for target rev age
    $temp = explode("Target Revision is from:",$cmd2);
    $temp = explode("Target Revision is ",$temp[1]);
    $temp = explode(" days old",$temp[1]);
    $fetch["target_rev_age"]=trim($temp[0]);

    // Search for target pilot perc
    $temp = explode("getperc says us",$cmd2);
    $temp = explode("top ",$temp[1]);
    $temp = explode("%",$temp[1]);
    $fetch["target_rev_pilot"]=trim($temp[0])."%";

    // Search for current rev age
    $temp = explode("\n",$cmd3);
    $tsrepo1="";
    $tsrepo2=0;
    foreach($temp as $line){
	if(empty($line)) continue;
	$line = trim($line);
	if(substr($line,0,23)=="Timestamp of repository"){
	    $stamp = explode(": ",$line);
	    $stamp = trim($stamp[1]);
	    $stampint = strtotime($stamp);
	    if($stampint>$tsrepo2){
		$tsrepo1=$stamp;
		$tsrepo2=$stampint;
	    }
	}
    }
    $fetch["currev_dt_str"]=$tsrepo1;
    $fetch["currev_dt_int"]=$tsrepo2;

    // Search for needrestart_phpsvc
    $temp_cnt=0;
    $temp_arr=array();
    foreach(explode("\n",$cmd4) as $line){
	if(substr($line,0,2)=="- "){
	    $temp_cnt++;
	    $temp_arr[]=substr(trim($line),2);
	}
    }
    $fetch["needrestart_phpsvc"]=$temp_cnt;
    $fetch["needrestart_phpsvc_details"]=$temp_arr;

    // Search for kernel upgrade pending
    $temp = explode("\nNEEDRESTART-KSTA: ",$cmd5);
    $temp = explode("\n",$temp[1]);
    $fetch["needrestart_app_kernel"]=0;
    if($temp[0]!=1) $fetch["needrestart_app_kernel"]=1;

    // Search for kernel microcode upgrade pending
    $temp = explode("\nNEEDRESTART-UCSTA: ",$cmd5);
    $temp = explode("\n",$temp[1]);
    $fetch["needrestart_app_ucode"]=0;
    if($temp[0]>1) $fetch["needrestart_app_ucode"]=1;

    // Search for service reboot
    $temp_cnt=0;
    $temp_arr=array();
    foreach(explode("\n",$cmd5) as $line){
	if(substr($line,0,17)=="NEEDRESTART-SVC: "){
	    $temp_cnt++;
	    $temp_arr[]=substr(trim($line),17);
	}
    }
    $fetch["needrestart_app_svc"]=$temp_cnt;
    $fetch["needrestart_app_svc_details"]=$temp_arr;

    // Search for not started services
    $in_shutdown=false;
    $temp_cnt=0;
    $temp_arr=array();
    foreach(explode("\n",$cmd7) as $line){
	$line=trim($line);
	if(stripos($line,"runlevel: ")!==false){
	    if(stripos($line,"shutdown")!==false){
		$in_shutdown=true;
	    }
	    else{
		$in_shutdown=false;
	    }
	}
	else{
	    if($in_shutdown) continue;
	    if(stripos($line,"stopped")!==false){
		$explode=explode("  ",$line);
		$temp_cnt++;
		$temp_arr[]=trim($explode[0]);
	    }
	}
    }
    $fetch["needrestart_rc_svc"]=$temp_cnt;
    $fetch["needrestart_rc_svc_details"]=$temp_arr;

    // Search for /run/needrestart - service
    $temp_cnt=0;
    $temp_arr=array();
    if(file_exists("/run/needrestart/service")){
	$scandir=scandir("/run/needrestart/service");
	foreach($scandir as $scanned){
	    if($scanned=="." || $scanned=="..") continue;
	    $temp_arr[]=$scanned;
	    $temp_cnt++;
	}
    }
    $fetch["needrestart_runneedrestart_svc"]=$temp_cnt;
    $fetch["needrestart_runneedrestart_svc_details"]=$temp_arr;

    // Search for /run/needrestart - system
    $temp_cnt=0;
    $temp_arr=array();
    if(file_exists("/run/needrestart/system")){
	$scandir=scandir("/run/needrestart/system");
	foreach($scandir as $scanned){
	    if($scanned=="." || $scanned=="..") continue;
	    $temp_arr[]=$scanned;
	    $temp_cnt++;
	}
    }
    $fetch["needrestart_runneedrestart_sys"]=$temp_cnt;
    $fetch["needrestart_runneedrestart_sys_details"]=$temp_arr;


    $fetch["config_outstanding"]=array();
    foreach(get_update_list() as $cfg_file=>$cfg_list){
	$fetch["config_outstanding"][]=$cfg_file;
    }

    if(stripos($cmd5,"NEEDRESTART-SESS")){
        $fetch["outdated_user_sessions"]=true;
    }
    else{
        $fetch["outdated_user_sessions"]=false;
    }

    $fetch["currev_no"]=get_svn_repo_info();
    $fetch["time"] = time();


    // Update Permanent Information, if we are at the right stage currently
    // Installed Packaged
    if($fetch["packages"]<1){
        $fetch["perm_last_fully_updated_rev"]=$fetch["currev_no"];
        $fetch["perm_last_fully_updated_dt"]=$fetch["currev_dt_int"];
    }
    else{
        $fetch["perm_last_fully_updated_rev"]=$permanent_data["perm_last_fully_updated_rev"];
        $fetch["perm_last_fully_updated_dt"]=$permanent_data["perm_last_fully_updated_dt"];
    }
    // Installed & Rebooted Packages
    if(
        $fetch["packages"]<1 &&
        $fetch["needrestart_phpsvc"]<1 &&
        $fetch["needrestart_app_svc"]<1 &&
        $fetch["needrestart_runneedrestart_svc"]<1 &&
        $fetch["needrestart_rc_svc"]<1 &&
        $fetch["needrestart_app_kernel"]<1 &&
        $fetch["needrestart_app_ucode"]<1 &&
        $fetch["outdated_user_sessions"]<1 &&
        $fetch["needrestart_runneedrestart_sys"]<1
    ){
        $fetch["perm_last_fully_updated_rebooted_rev"]=$fetch["currev_no"];
        $fetch["perm_last_fully_updated_rebooted_dt"]=$fetch["currev_dt_int"];
    }
    else{
        $fetch["perm_last_fully_updated_rebooted_rev"]=$permanent_data["perm_last_fully_updated_rebooted_rev"];
        $fetch["perm_last_fully_updated_rebooted_dt"]=$permanent_data["perm_last_fully_updated_rebooted_dt"];
    }
    // Installed & Configged Packages
    if($fetch["packages"]<1 && count($fetch["config_outstanding"])<1){
        $fetch["perm_last_fully_updated_configged_rev"]=$fetch["currev_no"];
        $fetch["perm_last_fully_updated_configged_dt"]=$fetch["currev_dt_int"];
    }
    else{
        $fetch["perm_last_fully_updated_configged_rev"]=$permanent_data["perm_last_fully_updated_configged_rev"];
        $fetch["perm_last_fully_updated_configged_dt"]=$permanent_data["perm_last_fully_updated_configged_dt"];
    }

    return($fetch);
}

function get_svn_repo_info()
{
    $rev = 0;
    $dirs = scandir("/var/db/repos");
    foreach ($dirs as $dir) {
        if ($dir == "." || $dir == "..") continue;
        if (!file_exists("/var/db/repos/" . $dir."/.svn")) continue;
        $thisrev = get_one_svn_repo_info($dir);
        if ($thisrev > $rev) {
            $rev = $thisrev;
        }
    }
    return ($rev);
}
function get_one_svn_repo_info($repo){
    $exec = shell_exec("svn info /var/db/repos/".$repo);

    $temp = explode("\nRevision: ",$exec);
    $temp = explode("\n",$temp[1]);
    $rev=trim($temp[0]);
    return($rev);
}



function get_update_list(){
    $chlist=array();

    $list = scandir_deep("/etc");
    foreach($list as $file){
	if(stripos($file,"._cfg")!==false){
	    $chfile=$file;
	    $pos = stripos($chfile,"._cfg");
	    $chfile=substr($file,0,$pos).substr($file,$pos+10);
	    $chlist[$chfile][]=$file;
	}
    }
    return($chlist);
}
function scandir_deep($path){
    $files=array();

    $scandir=scandir($path);
    foreach($scandir as $file){
	if($file=="." || $file=="..") continue;
	if(is_dir($path."/".$file)){
	    $multifiles=scandir_deep($path."/".$file);
	    foreach($multifiles as $file2){
		$files[]=$file2;
	    }
	}
	else{
	    $files[]=$path."/".$file;
	}
    }
    return($files);
}

function load_permanent_infos_from_cache(){
    $arr=array(
        "perm_last_fully_updated_rev"=>0,
        "perm_last_fully_updated_dt"=>0,
        "perm_last_fully_updated_rebooted_rev"=>0,
        "perm_last_fully_updated_rebooted_dt"=>0,
        "perm_last_fully_updated_configged_rev"=>0,
        "perm_last_fully_updated_configged_dt"=>0,
    );
    if(file_exists("/var/cache/update-status.db")){
        $fetch = unserialize(file_get_contents("/var/cache/update-status.db"));
        if(isset($fetch["perm_last_fully_updated_rev"])){
            $arr["perm_last_fully_updated_rev"]=$fetch["perm_last_fully_updated_rev"];
        }
        if(isset($fetch["perm_last_fully_updated_dt"])){
            $arr["perm_last_fully_updated_dt"]=$fetch["perm_last_fully_updated_dt"];
        }

        if(isset($fetch["perm_last_fully_updated_rebooted_rev"])){
            $arr["perm_last_fully_updated_rebooted_rev"]=$fetch["perm_last_fully_updated_rebooted_rev"];
        }
        if(isset($fetch["perm_last_fully_updated_rebooted_dt"])){
            $arr["perm_last_fully_updated_rebooted_dt"]=$fetch["perm_last_fully_updated_rebooted_dt"];
        }

        if(isset($fetch["perm_last_fully_updated_configged_rev"])){
            $arr["perm_last_fully_updated_configged_rev"]=$fetch["perm_last_fully_updated_configged_rev"];
        }
        if(isset($fetch["perm_last_fully_updated_configged_rev"])){
            $arr["perm_last_fully_updated_configged_rev"]=$fetch["perm_last_fully_updated_configged_rev"];
        }
    }
    return($arr);
}