]> Untitled Git - dev/commitdiff
Добавлены прочие проекты
authorsleepy <sleepy@vvsu.ru>
Tue, 28 Apr 2020 09:45:30 +0000 (19:45 +1000)
committersleepy <sleepy@vvsu.ru>
Tue, 28 Apr 2020 09:45:30 +0000 (19:45 +1000)
12 files changed:
dedupler/dedupler.php [new file with mode: 0644]
dedupler/dscd/dscd.php [new file with mode: 0644]
dedupler/dscd/libbox/mplib.php [new file with mode: 0644]
dedupler/dscd/libbox/timer.php [new file with mode: 0644]
dvblastmaster/dvbmaster.ini [new file with mode: 0644]
dvblastmaster/dvbmaster.php [new file with mode: 0644]
dvblastmaster/lib/mplib.php [new file with mode: 0644]
dvblastmaster/lib/sts.php [new file with mode: 0644]
dvblastmaster/lib/timer.php [new file with mode: 0644]
dvblastmaster/sigtest.php [new file with mode: 0644]
term/lowterm.php [new file with mode: 0644]
term/testterm.php [new file with mode: 0644]

diff --git a/dedupler/dedupler.php b/dedupler/dedupler.php
new file mode 100644 (file)
index 0000000..8a43459
--- /dev/null
@@ -0,0 +1,243 @@
+#!/usr/bin/env php
+<?php
+define('VERSION', '1.0a');
+function get_dir_tree($root)
+{
+    global $STH, $counter_dirs, $counter_files, $fh;
+    if (is_dir($root) === FALSE)
+    {
+       return FALSE;
+    }
+    $list = scandir($root);
+    foreach ($list as $item)
+    {
+       if ($item == '.' || $item == '..')
+       {
+           continue;
+       }
+       $path = $root.DIRECTORY_SEPARATOR.$item;
+       if (is_dir($path))
+       {
+           $counter_dirs ++;
+           get_dir_tree($path);
+       }
+       else
+       {
+           $counter_files ++;
+           $FIELD[0] = $path;
+           $FIELD[1] = filesize($path);
+           $STH->execute($FIELD);         
+       }
+    }
+echo "reading directory tree... $counter_dirs dirs $counter_files files \r";    
+}
+function help_topic($short = FALSE)
+{
+    global $argv;
+    echo 'File deduplicator ver. ', VERSION, PHP_EOL;
+    echo 'Usage: ', $argv[0],' [-options] directory',PHP_EOL;
+    echo 'Searches for identical files and allows you to remove duplicates', PHP_EOL ,'by deleting them or creating links instead.', PHP_EOL;
+    if ($short == TRUE)
+    {
+       echo 'Use -h for help.', PHP_EOL, PHP_EOL;
+       return;
+    }
+    $opts[] = '-n';
+    $descr[] = 'Action as do nothing (default).';
+    $opts[] = '-r';
+    $descr[] = 'Report to file in csv format, if file not set send to STDIN.';
+    $opts[] = '-d';
+    $descr[] = 'Delete duplicates. Conflict with -n -l -s.';
+    $opts[] = '-l';
+    $descr[] = 'Delete duplicates and create hardlinks. Duplicates must have same uid, gid and permissions, otherwise you should use -i. Conflict with -n -d -s.';
+    $opts[] = '-s';
+    $descr[] = 'Delete duplicates and create symlinks. Duplicates must have same uid, gid and permissions, otherwise you should use -i. Conflict with -n -d -l.';
+    $opts[] = '-i';
+    $descr[] = 'Ignore different uid, gid and permissions between duplicates. It will be used from the first file.';
+    $opts[] = '-h';
+    $descr[] = 'Show this help topic.';
+    $opts[] = '-v';
+    $descr[] = 'Be verbose while processing.';
+    $opts[] = '-V';
+    $descr[] = 'Show version.';
+
+    
+    echo 'options:', PHP_EOL;
+    foreach ($opts as $key => $val)
+    {
+       preg_match_all('/(.{0,60})(\ |$)/', $descr[$key],$parts);
+       foreach ($parts[1] as $part)
+       {
+           if ($part == '')
+           {
+               continue;
+           }
+           echo "\t", $val, "\t", $part, PHP_EOL;
+           $val = '';
+       }
+    }
+    echo PHP_EOL;
+}
+
+function reporter()
+{
+    global $opts;
+    if (!isset($opts['r']))
+    {
+       return;
+    }
+    
+}
+$counter_dirs = 0;
+$counter_files = 0;
+$tmpfile = '/tmp/dedupler.tmp';
+$optind = null;
+$opts = getopt('nrdlsihvV');
+var_dump($opts,$argv);
+if($argc > 1)
+{
+    $dir = array_pop ($argv);    
+}
+
+if ($argc == 1)
+{
+     help_topic(TRUE);
+    exit();
+}
+
+
+if (isset($opts['V']))
+{
+    echo VERSION,PHP_EOL;
+    exit();
+}
+
+if (isset($opts['h']))
+{
+    help_topic();
+    exit();
+}
+
+
+$colopts['n'] = FALSE;
+$colopts['d'] = FALSE;
+$colopts['l'] = FALSE;
+$colopts['s'] = FALSE;
+
+if (count(array_diff_key ($colopts,$opts)) < 3 )
+{
+    echo 'You can not use options -n, -d, -l, -s together in any combinations, because it conflict between themselves.', PHP_EOL;
+    exit(2);
+    
+}
+$_actmode = 0;
+
+if (isset($opts['d']))
+{
+    $_actmode = 1;
+}
+if (isset($opts['l']))
+{
+    $_actmode = 2;
+}
+if (isset($opts['s']))
+{
+    $_actmode = 3;
+}
+
+
+
+
+if (!is_dir($dir))
+{
+    echo $dir,' is not a directory!',PHP_EOL;
+    exit(1);
+}
+if (substr($dir, -1) == DIRECTORY_SEPARATOR)
+{
+    $dir = substr($dir,0,-1);
+}
+$_FSTREE = [];
+if (file_exists($tmpfile))
+{
+    unlink($tmpfile);
+}
+$DBH = new PDO("sqlite:".$tmpfile);
+$DBH->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
+$DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
+$DBH->exec ('CREATE TABLE fstree
+    (
+       id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+       path text,
+       size INTEGER            
+    )
+    '); 
+
+$STH = $DBH->prepare("INSERT INTO fstree (path, size) values (?, ?)");
+$DBH->beginTransaction();
+$tree = get_dir_tree($dir);
+$DBH->commit();
+$STH = $DBH->prepare("select path from fstree where size = ?");
+
+echo "\n";
+$stmt_sizes = $DBH->query('select size from fstree GROUP BY `size` HAVING count(*)>1');
+while ($size = $stmt_sizes->fetch())
+{
+    $size = implode($size);
+    echo PHP_EOL, "now analyzing group of files having size $size bytes:", PHP_EOL;
+    $STH->execute(array($size));
+    while ($path = $STH->fetch())
+    {  
+       $path = implode($path);
+       if (!is_link($path))
+       {
+           $stat = stat($path);
+           if (!isset($first_flag))
+           {
+               $first_path = $path;
+               unset($first_md5);
+               $first_inodev = $stat['dev']."+".$stat['ino'];
+               $first_uidgid = $stat['uid']."+".$stat['gid'];
+               $first_flag = TRUE;
+               echo $path, ' is first file',PHP_EOL;
+           }
+           else
+           {
+               $cmp_inodev = $stat['dev']."+".$stat['ino'];
+               $cmp_uidgid = $stat['uid']."+".$stat['gid'];
+               if ($first_inodev == $cmp_inodev)
+               {
+                   echo $path, ' is hardlink',PHP_EOL;
+                   continue;
+               }
+               if (!isset($first_md5))
+               {
+                   echo 'calculate md5 for first file',PHP_EOL;
+                   $first_md5 = md5_file($first_path);             
+               }
+               echo 'calculate md5 for next file',PHP_EOL;
+               $cmp_md5 = md5_file($path);
+               if ($first_md5 == $cmp_md5)
+               {
+                   echo $path, ' is copy',PHP_EOL;
+                   if ($mode == 0) 
+                   {
+                       
+                   }
+               }
+               else
+               {
+                   echo $path, ' is unique',PHP_EOL;
+
+               }
+           }
+           
+//         var_dump($path);
+//         var_dump(stat($path));
+           
+       }
+    }
+    unset($first_flag);
+    
+}
+
diff --git a/dedupler/dscd/dscd.php b/dedupler/dscd/dscd.php
new file mode 100644 (file)
index 0000000..3ac00fa
--- /dev/null
@@ -0,0 +1,8 @@
+<?php
+
+/* 
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
diff --git a/dedupler/dscd/libbox/mplib.php b/dedupler/dscd/libbox/mplib.php
new file mode 100644 (file)
index 0000000..ad311b1
--- /dev/null
@@ -0,0 +1,263 @@
+<?php\r
+\r
+/* \r
+ * To change this license header, choose License Headers in Project Properties.\r
+ * To change this template file, choose Tools | Templates\r
+ * and open the template in the editor.\r
+ */\r
+\r
+class Daemon\r
+{\r
+    private $unique_flag = FALSE;\r
+    private $pidfilename;\r
+\r
+    public function __construct()\r
+    {\r
+    }\r
+    \r
+    public function __destruct()\r
+    {\r
+       if ($this->unique_flag)\r
+       {\r
+           !unlink($this->pidfilename);\r
+       }\r
+       \r
+    }\r
+\r
+    public function daemonize()\r
+    {\r
+       $pid = pcntl_fork();\r
+       if ($pid == -1)\r
+        {\r
+                return FALSE;\r
+        }\r
+        elseif ($pid > 0)\r
+        {\r
+            exit;\r
+        }\r
+        umask(0);\r
+        chdir('/');\r
+        if (posix_setsid() == -1)\r
+        {\r
+           return FALSE;\r
+        }\r
+       \r
+       fclose(STDIN);\r
+       fclose(STDOUT);\r
+       fclose(STDERR);\r
+       $GLOBALS['STDIN'] = fopen('/dev/null', 'r');\r
+       $GLOBALS['STDOUT']= fopen('/dev/null', 'w');\r
+       $GLOBALS['STDERR'] = fopen('/dev/null', 'w');\r
+       \r
+       return TRUE;\r
+    }\r
+    \r
+    public function is_unique($pidfilename)\r
+    {\r
+       $mypid = posix_getpid();\r
+       if (is_readable($pidfilename))\r
+       {\r
+           $pid = (int)  rtrim(file_get_contents($pidfilename));\r
+           if ($pid == $mypid)\r
+           {\r
+               return TRUE;\r
+           }\r
+           if ($pid > 0 && posix_kill($pid, 0))\r
+           {\r
+               return FALSE;\r
+           }\r
+       }\r
+       return TRUE;\r
+\r
+    }\r
+    \r
+    public function no_unique($pidfilename)\r
+    {\r
+       if (!unlink($pidfilename))\r
+       {\r
+           return FALSE;\r
+       }\r
+    }\r
+\r
+    public function do_unique($pidfilename)\r
+    {\r
+       if (!$this->is_unique($pidfilename))\r
+       {\r
+           return FALSE;\r
+       }\r
+\r
+       $mypid = posix_getpid();\r
+       if (!file_put_contents($pidfilename, $mypid.PHP_EOL))\r
+       {\r
+           return FALSE;\r
+       }\r
+       return TRUE;\r
+    }\r
+}    \r
+\r
+class Children \r
+{\r
+    protected $PIPE;\r
+    protected $ROLE;\r
+    protected static $CHILDREN;\r
+    protected $CHILD;\r
+    protected $PARENT;\r
+\r
+\r
+    public function __construct()\r
+    {\r
+       self::set_sig_handlers();\r
+       $this->create_child();\r
+       switch ($this->ROLE)\r
+       {\r
+           case -1:\r
+               return FALSE;\r
+           case 0:\r
+               return TRUE;\r
+           case 1:\r
+               $this->ChildBody();\r
+               exit();\r
+       }\r
+       \r
+    }\r
+    \r
+    public function __destruct()\r
+    {\r
+       if ($this->ROLE == 0)\r
+       {\r
+           posix_kill($this->CHILD, SIGTERM);\r
+       }\r
+    }\r
+\r
+    protected function ChildBody()\r
+    {\r
+       \r
+    }\r
+\r
+    static function set_sig_handlers()\r
+    {\r
+       pcntl_signal(SIGCHLD, [__CLASS__, 'handler_sigchld']);\r
+    }\r
+    \r
+    public function SendUnixSignal($sig)\r
+    {\r
+       return posix_kill($this->CHILD, $sig);\r
+    }\r
+      \r
+    public function IsAlive()\r
+    {\r
+       if ($this->ROLE == 1)\r
+       {\r
+           return TRUE;\r
+       }\r
+       if (isset(self::$CHILDREN[$this->CHILD]))\r
+       {\r
+           return TRUE;\r
+       }\r
+       else\r
+       {\r
+           return FALSE;\r
+       }\r
+    }\r
+\r
+    public static function handler_sigchld()\r
+    {  \r
+       $pid = pcntl_waitpid(0, $status, WNOHANG);\r
+       if($pid > 0)\r
+       {\r
+           unset(self::$CHILDREN[$pid]);\r
+       }\r
+    }\r
+\r
+    protected function create_child()\r
+    {\r
+       $sockets = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);\r
+       stream_set_blocking ($sockets[0] , 0);\r
+       stream_set_blocking ($sockets[1] , 0);\r
+       $pid = pcntl_fork();\r
+       if ($pid == -1)\r
+       {\r
+           $this->ROLE = -1;\r
+           return FALSE;\r
+       }\r
+       elseif ($pid > 0)\r
+       {\r
+           // код для родителя\r
+           $this->CHILD = $pid;\r
+           self::$CHILDREN[$pid] = $pid;\r
+           $this->PARENT = FALSE;\r
+           $this->ROLE = 0;\r
+           $this->PIPE = &$sockets[0];\r
+           unset($sockets);\r
+       }\r
+       elseif ($pid == 0)\r
+       {\r
+           // код для ребёнка\r
+           $this->CHILD = FALSE;\r
+           $this->PARENT = posix_getppid();\r
+           $this->ROLE = 1;\r
+           $this->PIPE = &$sockets[1];\r
+           unset($sockets);\r
+       }\r
+       return TRUE;\r
+    }\r
+    \r
+    public function SendEvent($eventname, $data)\r
+    {\r
+       if (!is_resource($this->PIPE))\r
+       {\r
+           return FALSE;\r
+       }\r
+       $eventpack = base64_encode($eventname).chr(255).chr(0).chr(255).base64_encode(serialize($data)).chr(0).chr(15).chr(240).chr(255);\r
+       \r
+       $res = @stream_socket_sendto($this->PIPE, $eventpack);  \r
+       if ($res == -1)\r
+       {\r
+           return TRUE;\r
+       }\r
+       else\r
+       {\r
+           return FALSE;\r
+       }\r
+    }\r
+    \r
+    public function WaitEvent($wait = TRUE)\r
+    {\r
+       if (!is_resource($this->PIPE))\r
+       {\r
+           return FALSE;\r
+       }\r
+       \r
+       $r = [$this->PIPE];\r
+       if ($wait)\r
+       {\r
+           while (stream_select($r, $w, $x, 0) == 0)\r
+           {\r
+               usleep(10000);\r
+               $r = [$this->PIPE];\r
+           }\r
+       }\r
+       elseif (stream_select($r, $w, $x, 0) == 0)\r
+       {\r
+           return NULL;\r
+       }\r
+       $ipc_msg = '';\r
+       while (substr($ipc_msg , -4) != chr(0).chr(15).chr(240).chr(255))\r
+       {\r
+           $rcv_buf = stream_socket_recvfrom($this->PIPE, 1500);\r
+           var_dump($rcv_buf);\r
+           if ($rcv_buf == '')\r
+           {\r
+               return NULL;\r
+           }\r
+           $ipc_msg .= $rcv_buf;\r
+       }\r
+       $ipc_msg = substr($ipc_msg,0,-4);\r
+       $ipc_msg = explode(chr(255).chr(0).chr(255), $ipc_msg);\r
+       $retval['eventname'] = base64_decode($ipc_msg[0]);\r
+       $retval['data'] = unserialize(base64_decode($ipc_msg[1]));\r
+       \r
+       return $retval;\r
+       \r
+    }\r
+}\r
diff --git a/dedupler/dscd/libbox/timer.php b/dedupler/dscd/libbox/timer.php
new file mode 100644 (file)
index 0000000..0221bcb
--- /dev/null
@@ -0,0 +1,97 @@
+<?php
+register_tick_function(array('Timer','poll'));
+
+class Timer
+{
+    private $id; //метка
+    private $time; //таймер
+    private $IsStop; //флаг остановленности true/false
+    private $UserCall; //задача
+    private $UserCallArg; //параметр к задаче
+    private $StartTime; //момент запуска таймера
+    private $ltime; //оставшееся время
+    private $type; //тип true регенерируемый, false не регенерируемый
+    private static $timers = []; 
+
+    public function __construct($time, $callable,  $type = false) 
+    {
+        $this->id = uniqid();
+        $this->time = $time;
+        $this->UserCall = $callable;
+        $this->type = $type;
+        $this->start();
+        self::$timers[$this->id] = &$this;             
+    }
+
+    public function __destruct() 
+    {
+       unset(self::$timers[$this->id]);
+    }
+
+    private function getId()
+    {
+       return $this->id;
+    }
+
+    public function getTimeLeft()
+    {
+           return $this->ltime;
+    }
+
+    public function setTimeLeft($time)
+    {
+           $this->time = $time;
+    }
+
+
+    public function reset()
+    {
+       $this->StartTime = microtime(true);
+       $this->IsStop = FALSE;
+    }
+
+    public function start() 
+    {
+       $this->reset();
+       $this->IsStop = FALSE;
+    }
+
+    public function stop() 
+    {
+       $this->IsStop = TRUE;
+    }
+
+    public static function poll()
+    {
+       foreach (self::$timers as $timer)
+       {
+           if ($timer->IsStop == FALSE)
+           {
+               $timer->update();
+           }
+       }
+    }
+
+    private function update()
+    {
+       $this->ltime = $this->StartTime - microtime(true) + $this->time;
+       if ($this->ltime <= 0)
+       {
+           $this->ltime = 0;
+           $this->task();
+           if ($this->type == FALSE)
+           {
+               $this->stop();
+           }
+           else
+           {
+               $this->reset();
+           }
+       }
+    }
+
+    private function task() 
+    {
+       call_user_func_array ($this->UserCall, $this->UserCallArg = []);
+    }
+}
diff --git a/dvblastmaster/dvbmaster.ini b/dvblastmaster/dvbmaster.ini
new file mode 100644 (file)
index 0000000..e359723
--- /dev/null
@@ -0,0 +1,52 @@
+[common]
+pidfile = /var/run/dvbmaster.pid
+dvblast_path = /usr/local/bin/dvblast
+dvblastctl_path = /usr/local/bin/dvblastctl
+es_timeout = 3000
+epg_passthrough = yes
+;provider_name = pizda
+;network_id = azaz
+;network_name = aaaa
+ttl = 64
+use_rtp = yes
+pidmap = 100,200,300,400
+run_user = nobody
+run_group = video
+
+
+[adapters]
+podryad1 = /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8.3
+podryad2 = /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8.2
+adap1 = /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8.1/1-8.1.2
+adap2 = /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8.1/1-8.1.4
+
+[enable]
+;podryad1 = mux-1
+podryad2 = mux-1
+;adap1 = off
+adap2 = mux-1
+
+[mux-1]
+delivery_system = DVBC_ANNEX_A
+frequency = 778000000
+symbol_rate = 6875000
+out[] = 239.1.2.51:2020 1 2701
+out[] = 239.1.2.52:2020 1 2702
+out[] = 239.1.2.53:2020 1 2703
+out[] = 239.1.2.54:2020 1 2704
+out[] = 239.1.2.55:2020 1 2705
+out[] = 239.1.2.56:2020 1 2706
+out[] = 239.1.2.57:2020 1 2707
+out[] = 239.1.2.58:2020 1 2708
+out[] = 239.1.2.59:2020 1 2709
+out[] = 239.1.2.60:2020 1 2710
+out[] = 239.1.2.61:2020 1 2711
+out[] = 239.1.2.62:2020 1 2712
+out[] = 239.1.2.63:2020 1 2713
+
+
+[mux-2]
+delivery_system = DVBT2
+frequency = 610000000
+symbol_rate = 6875000
+plp_id = 0
\ No newline at end of file
diff --git a/dvblastmaster/dvbmaster.php b/dvblastmaster/dvbmaster.php
new file mode 100644 (file)
index 0000000..177e575
--- /dev/null
@@ -0,0 +1,897 @@
+#!/usr/bin/env php
+<?php
+// library 
+require_once 'lib/sts.php';
+require_once 'lib/mplib.php';
+require_once 'lib/timer.php';
+
+// main code class 
+class dvbmaster
+{
+    protected $IniConfig;
+    protected $IniFile = 'dvbmaster.ini';
+    protected $WorkCommonParams = [];
+    protected $WorkAdaptersCfg = [];
+    protected $Multiplexes = [];
+    protected $dvblastctl;
+    protected $RUN = FALSE;
+    protected $XmlStatsData = [];
+    protected $RunAsDaemon = FALSE;
+
+    public function __construct()
+    {
+       $this->CliParseOptions();
+       STS::stdout_prefix('dvbmaster: ');
+       
+       declare(ticks = 1);
+       cli_set_process_title('dvbmaster: master process');
+       if (!$this->ReadConfig())
+       {
+           echo "ERROR: Reading config file error!\n";
+           exit();
+       }
+       if (!isset($this->WorkCommonParams['pidfile']))
+       {
+           echo "ERROR: Pidfile not defined in config file!\n";
+           exit();
+       }
+       $_PIDFILENAME = &$this->WorkCommonParams['pidfile'];
+
+       if ($this->RunAsDaemon)
+       {
+           Daemon::daemonize();
+       }
+       if (!Daemon::is_unique($_PIDFILENAME))
+       {
+           echo "ERROR: This program already runed!\n";
+           exit();
+       }
+       if (!Daemon::do_unique($_PIDFILENAME))
+       {
+           echo "ERROR: Can't make this program instance is unique!\n";
+           exit();
+           
+       }
+       $this->SetUidGid();
+       
+       pcntl_signal(SIGHUP, [$this, 'handler_sighup']);
+       pcntl_signal(SIGTERM, [$this, 'handler_sigintterm']);
+       pcntl_signal(SIGINT, [$this, 'handler_sigintterm']);
+       
+
+       $this->dvblastctl = new dvblastctl();
+       $this->dvblastctl->SendEvent('updateconfig', $this->GetConfigForDvblastctl());
+       $this->RUN = TRUE;
+       while ($this->RUN)
+       {
+           $this->loop();
+           sleep(1);
+       }
+       $this->WaitForShutdown();
+       
+    }
+    
+    public function __destruct()
+    {
+       STS::stdout_unprefix();
+       
+    }
+    public function handler_sighup()
+    {
+       echo "Got SIGHUP, rereading configuration file...\n";
+       if (!$this->ReadConfig())
+       {
+           echo "Reading config error!\n";
+       }
+       else
+       {
+           $this->dvblastctl->SendEvent('updateconfig', $this->GetConfigForDvblastctl());
+           
+           echo "Reread configuration file is finished!\n";
+       }
+    }
+
+    public function handler_sigintterm()
+    {
+       echo "Got SIGINT/SIGTERM, wait for the completion of worker processes...\n";
+       $this->RUN = FALSE;
+       $this->dvblastctl->SendEvent('shutdown', NULL);
+    }
+    protected function WaitForShutdown()
+    {
+       for ($c = 0; $c < 15; $c++)
+       {
+           sleep(1);
+           if (!$this->dvblastctl->IsAlive())
+           {
+               break;
+           }
+           
+       }
+       
+       
+       
+    }
+
+    public function loop()
+    {
+       echo 'LOOP'.PHP_EOL;
+       $this->EventReciever();
+    }
+    
+    protected function EventReciever()
+    {
+       while (($DvblastctlMessage = $this->dvblastctl->WaitEvent(FALSE)) !== NULL && $DvblastctlMessage !== FALSE)
+       {
+               $this->EventProcessor('dvblastctl',$DvblastctlMessage);
+       }
+    }
+    
+    protected function EventProcessor($module, $message)
+    {
+       if ($module == 'dvblastctl')
+       {
+           switch ($message['eventname'])
+           {
+               case 'updatestats':
+                   $this->XmlStatsData = array_replace_recursive($this->XmlStatsData,  $message['data']);
+                   break;
+
+           }
+       }
+    }
+
+
+    // сканер физических устройств DVB
+    // вход: нет
+    // выход array устройства из udev
+    public function ScanDvbDevices()
+    {
+
+       echo 'scan devices...',PHP_EOL;
+       if (!file_exists('/dev/dvb/'))
+       {
+           exit("dvb frontend devices not found\n");
+       }
+       else
+       {
+           exec ('find /dev/dvb/ -name "frontend*"', $devnames);
+           if (count($devnames) == 0)
+           {
+               exit("dvb frontend devices not found\n");
+           }
+       }
+       $DVBDevs = [];
+       foreach ($devnames as $devname)
+       {
+           exec ('udevadm info '.$devname, $devinfo);
+           foreach ($devinfo as $str)
+           {
+               if(preg_match('/^.:\s(.+)=(.*)$/', $str, $d) > 0)
+               {
+                   $DVBDevs[$devname][$d[1]] = $d[2];
+               }
+               if (isset($DVBDevs[$devname]['DEVPATH']))
+               {
+                   $DVBDevs[$devname]['DEVPORT'] = preg_replace ('/\/dvb\/.*/', '', $DVBDevs[$devname]['DEVPATH']);
+               }
+
+           }
+           unset($devinfo,$d,$str);
+       }
+       return $DVBDevs;
+    }
+    
+    
+    public function GenerateDevConfig($DVBDevs)
+    {
+       $adaptername = 0;
+       $ini = [];
+       foreach ($DVBDevs as $name => $data)
+       {
+           $ini['adapters']['adaptername-'.$adaptername] = $data['DEVPORT']; 
+
+           $adaptername++;
+       }
+       echo STS::generate_ini($ini);
+    }
+
+    public function HelpTopic()
+    {
+       echo "This is a help topic \n";
+    }
+
+    public function CliParseOptions()
+    {
+       $shortoptlist = 'hsdc:';
+       $longoptlist = ['help','scandev', 'daemon', 'config-file:'];
+       $opts = getopt($shortoptlist, $longoptlist, $optindex);
+       var_dump($opts, $optindex);
+
+       if (isset($opts['h']) || isset($opts['help']))
+       {
+           $this->HelpTopic();
+           exit();
+       }
+
+       if (isset($opts['s']) || isset($opts['scandev']))
+       {
+           $scandev = $this->ScanDvbDevices();
+           echo "\n;Insert this output to your configuration file (.ini) file.\n\n";
+           $this->GenerateDevConfig($scandev);
+           exit();
+       }
+
+       if (isset($opts['d']) || isset($opts['daemon']))
+       {
+           $this->RunAsDaemon = TRUE;
+       }
+       
+       if (isset($opts['c']))
+       {
+           $IniFile = $opts['c'];
+       }       
+
+       if (isset($opts['config-file']))
+       {
+           $IniFile = $opts['config-file'];
+       }       
+       if (is_string($IniFile))
+       {
+           $this->IniFile = $IniFile;
+       }
+       
+    }
+
+    public function ReadConfig()
+    {
+       $ini_file = &$this->IniFile;
+       if (!file_exists($ini_file))
+       {
+           echo "ERROR: Configuration file {$ini_file} not found. \n";
+           return FALSE;
+       }
+       $this->IniConfig = @parse_ini_file($ini_file, TRUE, INI_SCANNER_TYPED);
+       if ($this->IniConfig === FALSE)
+       {
+           echo "ERROR: Configuration file {$ini_file} contain syntax errors. \n";
+           return FALSE;
+       }
+       if (!isset($this->IniConfig['adapters']))
+       {
+           return FALSE;
+       }
+       
+       $this->Multiplexes = [];
+       $this->WorkAdaptersCfg = [];
+       $this->WorkCommonParams = [];
+       
+       $ScannedDevs = $this->ScanDvbDevices();
+       foreach ($this->IniConfig['adapters'] as $AdapterName => $AdapterPort)
+       {
+           foreach ($ScannedDevs as $Dev)
+           {
+               if ($AdapterPort == $Dev['DEVPORT'])
+               {
+                   $this->WorkAdaptersCfg[$AdapterName]['DEVNAME'] = $Dev['DEVNAME'];
+                   $this->WorkAdaptersCfg[$AdapterName]['ADAPTER_NUM'] = $Dev['DEVPORT'];
+                   $this->WorkAdaptersCfg[$AdapterName]['ADAPTER_NUM'] = $Dev['DVB_ADAPTER_NUM'];
+                   $this->WorkAdaptersCfg[$AdapterName]['FRONTEND_NUM'] = $Dev['DVB_DEVICE_NUM'];
+                   if (isset($this->IniConfig['enable'][$AdapterName]))
+                   {
+                       $this->WorkAdaptersCfg[$AdapterName]['MUX'] = $this->IniConfig['enable'][$AdapterName];
+                   }
+                   else
+                   {
+                       $this->WorkAdaptersCfg[$AdapterName]['MUX'] = FALSE;
+                   }
+               }
+           }
+       }
+       $ValidDelSys = ['DVBS', 'DVBS2', 'DVBC_ANNEX_A', 'DVBT','DVBT2', 'ATSC','ISDBT','DVBC_ANNEX_B'];
+       $ValidModulationC = ['qpsk','qam_16','qam_32','qam_64','qam_128','qam_256'];
+       $ValidModulationT = ['qam_16','qam_32','qam_64','qam_128','qam_256'];
+       $ValidModulationS = ['qpsk','psk_8','apsk_16','apsk_32'];
+       foreach ($this->IniConfig as $SectionName => $Section)
+       {
+           if (isset($Section['delivery_system']))
+           {
+               if(array_search($Section['delivery_system'], $ValidDelSys) !== FALSE)
+               {
+                   $this->Multiplexes[$SectionName] = $Section;
+                   
+               }
+               if (isset($this->Multiplexes[$SectionName]['modulation']))
+               {
+                   $modname = $this->Multiplexes[$SectionName]['modulation'];
+                   if (($this->Multiplexes[$SectionName]['delivery_system'] == 'DVBS' || $this->Multiplexes[$SectionName]['delivery_system'] == 'DVBS2') && array_search($this->Multiplexes[$SectionName]['modulation'], $ValidModulationS) === FALSE)
+                   {
+                       $this->Multiplexes[$SectionName]['modulation'] = FALSE;         
+                   }
+                   if (($this->Multiplexes[$SectionName]['delivery_system'] == 'DVBC_ANNEX_A' || $this->Multiplexes[$SectionName]['delivery_system'] == 'DVBC_ANNEX_B')&& array_search($this->Multiplexes[$SectionName]['modulation'], $ValidModulationC) === FALSE)
+                   {
+                       $this->Multiplexes[$SectionName]['modulation'] = FALSE;         
+                   }
+                   if (($this->Multiplexes[$SectionName]['delivery_system'] == 'DVBT' || $this->Multiplexes[$SectionName]['delivery_system'] == 'DVBT2')&& array_search($this->Multiplexes[$SectionName]['modulation'], $ValidModulationT) === FALSE)
+                   {
+                       $this->Multiplexes[$SectionName]['modulation'] = FALSE;         
+                   }
+                   if ($this->Multiplexes[$SectionName]['modulation'] === FALSE)
+                   {
+                       echo "WARNING: In MUX '{$SectionName}' modulation '{$modname}' can't be used with system {$this->Multiplexes[$SectionName]['delivery_system']}, using default.\n";
+                       unset($this->Multiplexes[$SectionName]['modulation']);
+                   }
+               }
+           }
+       }
+       
+       foreach ($this->WorkAdaptersCfg as $AdapterName => $AdapterCfg)
+       {
+           if ($AdapterCfg['MUX'] === FALSE)
+           {
+               continue;
+           }
+           if (!isset($this->Multiplexes[$AdapterCfg['MUX']]))
+           {
+               echo "ERROR: Multiplex configuration with name {$AdapterCfg['MUX']} for adapter {$AdapterName} not found.\n";
+               return FALSE;
+           }
+       }
+       
+       if (!isset($this->IniConfig['common']['dvblast_path']))
+       {
+           echo "ERROR: Common configuration 'dvblast_path' not found\n";
+           return FALSE;
+       }
+       if (!isset($this->IniConfig['common']['dvblastctl_path']))
+       {
+           echo "ERROR: Common configuration 'dvblastctl_path' not found\n";
+           return FALSE;
+       }
+       if (!file_exists($this->IniConfig['common']['dvblast_path']))
+       {
+           echo "ERROR: File in 'dvblast_path' not found\n";
+           return FALSE;
+       }
+       if (!file_exists($this->IniConfig['common']['dvblastctl_path']))
+       {
+           echo "ERROR: File in 'dvblastctl_path' not found\n";
+           return FALSE;
+       }
+       
+       $this->WorkCommonParams = $this->IniConfig['common'];    
+       return TRUE;
+       
+    }
+    
+    public function GetConfigForDvblastctl()
+    {
+       $config = [];
+       $config['Multiplexes'] = $this->Multiplexes;
+       $config['WorkAdaptersCfg'] = $this->WorkAdaptersCfg;
+       $config['WorkCommonParams'] = $this->WorkCommonParams;
+       return $config;
+    }
+    
+    public function SetUidGid()
+    {
+       $FAILFLAG = FALSE;
+       $_PIDFILENAME = &$this->WorkCommonParams['pidfile'];
+       if (isset($this->WorkCommonParams['run_group']))
+       {           
+           if(!chgrp($_PIDFILENAME, $this->WorkCommonParams['run_group']))
+           {
+               echo 'WARNING: Could not change group for file ',$_PIDFILENAME;
+           }
+           echo "Set process group (GID) to {$this->WorkCommonParams['run_group']} ...";
+           $userinfo = posix_getgrnam($this->WorkCommonParams['run_group']);
+           if ($userinfo === FALSE)
+           {
+               echo "FAIL\n";
+               $FAILFLAG = TRUE;
+               
+           }
+           elseif (!posix_setgid($userinfo['gid']))
+           {
+               echo "FAIL\n";
+               $FAILFLAG = TRUE;
+           }
+                   else
+           {
+               echo "DONE\n";
+           }
+       }
+       if (isset($this->WorkCommonParams['run_user']))
+       {
+           if(!chown($_PIDFILENAME, $this->WorkCommonParams['run_user']))
+           {
+               echo 'WARNING: Could not change user for file ',$_PIDFILENAME;
+           }
+           echo "Set process user (UID) to {$this->WorkCommonParams['run_user']} ...";
+           $userinfo = posix_getpwnam($this->WorkCommonParams['run_user']);
+           if ($userinfo === FALSE)
+           {
+               echo "FAIL\n";
+               $FAILFLAG = TRUE;
+               
+           }
+           elseif (!posix_setuid($userinfo['uid']))
+           {
+               echo "FAIL\n";
+               $FAILFLAG = TRUE;
+           }
+           else
+           {
+               echo "DONE\n";
+           }
+       }
+
+       return !$FAILFLAG;
+    }
+    
+}
+// класс контроллера процессов dvblast
+class dvblastctl extends Children
+{
+    protected $PIPES = [];
+    protected $dvbprc = [];
+    protected $runcmd = [];
+    protected $errbuffer = [];
+    protected $RestartFlag = [];
+    protected $config;
+    protected $wdlock = FALSE;
+    protected $usdlock = FALSE;
+    protected $timers = [];
+    protected $RUN = TRUE;
+    protected $StatMd5 = [];
+    protected $QueueUpdateStatData = [];
+
+
+    public function handler_sig($SIG)
+    {
+       $SIGMNEMO = STS::GetSignalMnemonicByNumber($SIG);
+       if ($SIGMNEMO === FALSE)
+       {
+           $SIGMNEMO = 'unknown';
+       }
+       $this->wdlock = TRUE;
+       echo "Got '{$SIGMNEMO}' ({$SIG}) signal! Shutting down all dvblast process...\n";
+       $this->timers['WatchdogDvblast']->stop();
+       $this->timers['UpdateMsgBuffer']->stop();
+       $this->timers['GetMsgBuffer']->stop();
+       foreach ($this->dvbprc as $procname => $procdesc)
+       {
+            $this->StopDvblast($procname);
+       }   
+       echo "All processes was shuted down.\n";
+       $this->RUN = FALSE;
+       
+    }
+
+    public function __destruct()
+    {
+       parent::__destruct();
+       if ($this->ROLE == MPRole_CHILD)
+       {
+           STS::stdout_unprefix();
+       }
+       
+    }
+    protected function ChildBody($INPARAM)
+    {
+       //init
+       declare(ticks = 1);
+       cli_set_process_title('dvblastctl: controller process');
+       unset($GLOBALS['PRG']);
+       STS::stdout_unprefix();
+       STS::stdout_prefix('dvblastctl: ');
+       pcntl_signal(SIGTERM, [&$this, 'handler_sig']);
+       pcntl_signal(SIGINT, [&$this, 'handler_sig']);
+       pcntl_signal(SIGHUP,SIG_IGN);
+       echo "remove temporary files...";
+       @array_map('unlink', glob("/tmp/*.dvbmcfg"));
+       echo "DONE\n";
+       //get config after starts
+       echo "wait for config...";
+       $event = $this->WaitEvent(TRUE);
+       if ($event['eventname'] != 'updateconfig')
+       {
+           echo "FAIL\nERROR: fetched is not config.\n";
+           exit(1);
+       }
+       $this->config = $event['data'];
+       echo "DONE\n";
+       
+       //start dvblast pool
+       $CmdParams = $this->PrepareDvblastParams($this->config);
+
+       foreach ($CmdParams as $NameInstance => $CmdParam)
+       {
+           $this->StartDvblast($NameInstance, $CmdParam);          
+       }
+       $ListUpdateStatData = ['fe_status' => 60, 'mmi_status' => 100, 'get_pat' => 300, 'get_cat' => 300, 'get_nit' => 300, 'get_sdt' => 300, 'get_pids' => 10];
+       $this->timers['WatchdogDvblast'] = new Timer(30, [$this, 'WatchdogDvblast'], NULL, TRUE);
+       $this->timers['UpdateMsgBuffer'] = new Timer(10, [$this, 'UpdateMsgBuffer'], NULL, TRUE);
+       $this->timers['UpdateStatData'] = new Timer(10, [$this, 'UpdateStatData'], NULL, TRUE);
+       $this->timers['GetMsgBuffer'] = new Timer(3600, [$this, 'GetMsgBuffer'], NULL, TRUE);
+       foreach ($ListUpdateStatData as $infcmd => $time)
+       {
+           $this->timers['AddToQueueUpdateStatData'] = new Timer($time, [$this, 'AddToQueueUpdateStatData'], [$infcmd], TRUE);
+           $this->AddToQueueUpdateStatData($infcmd);
+       }
+       while ($this->RUN)
+       {
+           sleep(1);
+           $this->loop();
+       }
+       echo "Shuted down controller process\n";
+       STS::stdout_unprefix();
+    }
+
+    protected function EventProcessor()
+    {
+       while (($event = $this->WaitEvent(FALSE)) !== NULL && $event !== FALSE)
+       {
+           switch ($event['eventname'])
+           {
+               case 'updateconfig':
+                   $this->ReuseConfig($event['data']);
+                   break;
+               case 'shutdown':
+                   $this->handler_sig(3);
+                   break;
+           }
+       }
+    }
+     
+    protected function ReuseConfig($NewConfig)
+    {
+       $result = array_udiff_assoc($NewConfig, $this->config,  function ($a, $b) {return (int)!($a === $b);});
+       $stoplist = [];
+       $startlist = [];
+       if (isset($result['WorkCommonParams']))
+       {
+           $stoplist = array_keys($this->dvbprc);
+           foreach ($stoplist as $AdapterName)
+           {
+               $this->StopDvblast($AdapterName);
+           }
+           $this->config = $NewConfig;
+           $CmdParams = $this->PrepareDvblastParams($this->config);
+           foreach ($CmdParams as $NameInstance => $CmdParam)
+           {
+               $this->StartDvblast($NameInstance, $CmdParam);      
+           }
+           return;
+       }
+       if (isset($result['WorkAdaptersCfg']))
+       {           
+           $stoplist = array_keys(array_udiff_assoc($this->config['WorkAdaptersCfg'], $NewConfig['WorkAdaptersCfg'],  function ($a, $b) {return (int)!($a === $b);}));
+           $startlist = array_keys(array_udiff_assoc($NewConfig['WorkAdaptersCfg'], $this->config['WorkAdaptersCfg'],  function ($a, $b) {return (int)!($a === $b);})); 
+       }       
+       if (isset($result['Multiplexes']))
+       {
+           $omux = array_keys(array_udiff_assoc($this->config['Multiplexes'], $NewConfig['Multiplexes'],  function ($a, $b) {return (int)!($a === $b);}));
+           $diffmux = array_keys(array_udiff_assoc($NewConfig['Multiplexes'], $this->config['Multiplexes'],  function ($a, $b) {return (int)!($a === $b);}));
+           foreach ($this->config['WorkAdaptersCfg'] as $AdapterName => $AdapterConfig)
+           {
+               if (array_search($AdapterConfig['MUX'], $omux) !== FALSE)
+               {
+                   $stoplist[] = $AdapterName;
+               }
+           }
+           foreach ($NewConfig['WorkAdaptersCfg'] as $AdapterName => $AdapterConfig)
+           {
+               if (array_search($AdapterConfig['MUX'], $diffmux) !== FALSE)
+               {
+                   $startlist[] = $AdapterName;
+               }
+           }
+           
+       }
+       
+       $stoplist = array_unique($stoplist);
+       $startlist = array_unique($startlist);
+       foreach ($stoplist as $NameInstance)
+       {
+           if (isset($this->dvbprc[$NameInstance]))
+           {
+               $this->StopDvblast($NameInstance);
+           }
+       }
+       
+       $this->config = $NewConfig;
+       $CmdParams = $this->PrepareDvblastParams($this->config);
+       foreach ($startlist as $NameInstance)
+       {
+           if (isset($CmdParams[$NameInstance]))
+           {
+               $this->StartDvblast($NameInstance, $CmdParams[$NameInstance]);
+           }       
+       }
+
+    }
+
+    public function AddToQueueUpdateStatData($infcmd)
+    {
+       $this->QueueUpdateStatData[] = $infcmd;
+    }
+    
+    public function UpdateStatData()
+    {
+       if ($this->wdlock || $this->usdlock)
+       {
+           return;
+       }
+       $this->usdlock = TRUE;
+       $AdapterNames = array_keys($this->dvbprc);
+       $this->QueueUpdateStatData = array_unique($this->QueueUpdateStatData);
+       while (count($this->QueueUpdateStatData) > 0)
+       {
+           $infcmd = array_pop($this->QueueUpdateStatData);
+           foreach ($AdapterNames as $AdapterName)
+           {
+               $cmd = $this->config['WorkCommonParams']['dvblastctl_path'].' -r /tmp/dvb-'.$AdapterName.'.sock -t 5 -x xml ';
+                   $xml = shell_exec($cmd.$infcmd.' 2>&1');
+                   if (!isset($this->StatMd5[$AdapterName][$infcmd]))
+                   {
+                       $this->StatMd5[$AdapterName][$infcmd] = NULL;
+                   }
+                   $XmlMd5 = md5($xml);
+                   if ($this->StatMd5[$AdapterName][$infcmd] == $XmlMd5)
+                   {
+                       continue;
+                   }
+                   $this->StatMd5[$AdapterName][$infcmd] = $XmlMd5;
+                   unset($SendData);
+                   $SendData[$AdapterName][$infcmd] = $xml;
+                   $this->SendEvent('updatestats', $SendData);
+           }
+       }
+       $this->usdlock = FALSE;
+    }
+
+    protected function StartDvblast($name,$runcmd)
+    {
+       $this->wdlock = TRUE;
+       $descriptorspec = [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']];
+       echo "starting process '{$name}'...";
+       $this->runcmd[$name] = $runcmd;
+       $this->errbuffer[$name] = [];
+       $this->dvbprc[$name] = proc_open('exec '.$runcmd, $descriptorspec, $this->PIPES[$name]);        
+       foreach ($this->PIPES[$name] as $procpipe)
+       {
+           stream_set_blocking($procpipe,0);
+       }
+       $procstatus = proc_get_status($this->dvbprc[$name]);
+       if ($procstatus['running'])
+       {
+           echo "OK\n";            
+       }
+       else
+       {
+           echo "FAIL\n";
+           $this->StopDvblast($name);
+       }
+       $this->wdlock = FALSE;
+       new Timer(3, [$this, 'WatchdogDvblast'], NULL, NULL);
+    }
+    protected function StopDvblast($name)
+    {
+       $this->wdlock = TRUE;
+       echo "shutdown process '{$name}'...";
+       proc_terminate ($this->dvbprc[$name]);
+       for ($i=0;$i<10;$i++) 
+       {
+           $procstatus = proc_get_status($this->dvbprc[$name]);
+           if (!$procstatus['running'])
+           {
+               break;
+           }
+           sleep(1);
+           echo '.';
+       }
+       if ($procstatus['running'])
+       {
+           proc_terminate ($this->dvbprc[$name],SIGTERM);
+           echo "FAIL\nWARNING: The process '{$name}' did not complete normally.\n";
+       }
+       else
+       {
+           echo "DONE\n";          
+       }
+       stream_get_contents($this->PIPES[$name][1]);
+       stream_get_contents($this->PIPES[$name][2]);
+       foreach ($this->PIPES[$name] as $procpipe)
+       {
+           fclose($procpipe);
+       }
+       proc_close($this->dvbprc[$name]);
+       unset($this->PIPES[$name], $this->dvbprc[$name], $this->runcmd[$name], $this->errbuffer[$name]);
+       $this->wdlock = FALSE;
+    }
+    
+    public function UpdateMsgBuffer()
+    {
+       if ($this->wdlock)
+       {
+           return;
+       }
+       foreach ($this->PIPES as $name => $PIPE)
+       {
+           do 
+           {
+               $str = fgets($PIPE[2]);
+               $ParsedStr = explode(':', $str, 2);
+               if ($ParsedStr[0] == 'error')
+               {
+                   if (isset($ParsedStr[1]))
+                   $this->errbuffer[$name][] = ltrim (rtrim ($ParsedStr[1]));
+               }
+               
+           }
+           while ($str !== FALSE);
+       }
+    }
+    
+    protected function GetMsgBuffer($name)
+    {
+       $messages = $this->errbuffer[$name];
+       $this->errbuffer[$name] = [];
+       return $messages;
+    }
+
+    public function ResetRestartFlag($name)
+    {
+       unset ($this->RestartFlag[$name]);
+    }
+
+    public function WatchdogDvblast()
+    {
+       if ($this->wdlock)
+       {
+           return;
+       }
+       foreach ($this->dvbprc as $name => $dvbprcres)
+       {
+           $procstatus = proc_get_status($dvbprcres);
+           if (!$procstatus['running'])
+           {
+               $this->UpdateMsgBuffer();
+               $errbuff = $this->GetMsgBuffer($name);
+               if (isset($this->RestartFlag[$name]))
+               {
+                   echo "WARNING: The process '{$name}' unexpectedly crashed repeatedly! Abort respawn procedure.\n";
+                   $this->StopDvblast($name);
+               }
+               else
+               {
+                   $this->UpdateMsgBuffer();
+                   $this->GetMsgBuffer($name);
+                   echo "WARNING: The process '{$name}' unexpectedly crashed. Try to respawn...\n";            
+                   $runcmd = $this->runcmd[$name];
+                   $this->StopDvblast($name);
+                   $this->StartDvblast($name, $runcmd);
+                   $this->RestartFlag[$name] = TRUE;
+                   new Timer(8, [$this, 'ResetRestartFlag'],[$name], NULL);
+                   new Timer(5, [$this, 'WatchdogDvblast'], NULL, NULL);
+               }
+               if (count($errbuff) > 0)
+               {
+                   echo "The process '{$name}' returns the following error messages:\n";
+                   echo implode("\n", $errbuff),"\n";
+               }
+           }
+       }
+    }
+    
+    protected function loop()
+    {
+       
+       $this->EventProcessor();
+    }
+
+        protected function PrepareDvblastParams ($_CONFIG)
+    {
+       $shellcmd = [];
+       $commonparams = '';
+       foreach ($_CONFIG['WorkCommonParams'] as $option => $value)
+       {
+           switch ($option)
+           {
+               case 'es_timeout':
+                   $commonparams .= '-7 '.(integer)$value.' ';
+                   break;
+               case 'provider_name':
+                   $commonparams .= '-B '.$value.' ';
+                   break;
+               case 'network_id':
+                   $commonparams .= '-N '.(integer)$value.' ';
+                   break;
+               case 'network_name':
+                   $commonparams .= '-M '.$value.' ';
+                   break;
+               case 'ttl':
+                   if ($value > 1 && $value <256)
+                   {
+                       $commonparams .= '-t '.(integer)$value.' ';                     
+                   }
+                   else
+                   {
+                       echo "ERROR: Invalid 'ttl' options value in config, default value will be used.\n";
+                   }
+                   break;
+               case 'pidmap':
+                   $commonparams .= '-0 '.$value.' ';
+                   break;
+               case 'use_rtp':
+                   if ($value === FALSE)
+                   {
+                       $commonparams .= '-U ';
+                   }
+                   break;
+               case 'epg_passthrough':
+                   if ($value === TRUE)
+                   {
+                       $commonparams .= '-e ';     
+                   }
+                   break;
+           }
+       }
+       foreach ($_CONFIG['WorkAdaptersCfg'] as $AdapterName => $AdapterCfg)
+       {
+           if ($AdapterCfg['MUX'] === FALSE)
+           {
+               continue;
+           }
+           $shellcmd[$AdapterName] = $_CONFIG['WorkCommonParams']['dvblast_path'].' ';
+           foreach ($AdapterCfg as $option => $value)
+           {
+               switch ($option)
+               {
+                   case 'ADAPTER_NUM':
+                       $shellcmd[$AdapterName] .= '-a '.(integer)$value.' ';
+                       break;
+                   case 'FRONTEND_NUM':
+                       $shellcmd[$AdapterName] .= '-n '.(integer)$value.' ';
+                       break;
+               }
+           }
+           foreach ($_CONFIG['Multiplexes'][$AdapterCfg['MUX']] as $option => $value)
+           {
+               switch ($option)
+               {
+                   case 'delivery_system':
+                       $shellcmd[$AdapterName] .= '-5 '.$value.' ';
+                       break;
+                   case 'frequency':
+                       $shellcmd[$AdapterName] .= '-f '.(integer)$value.' ';
+                       break;
+                   case 'symbol_rate':
+                       $shellcmd[$AdapterName] .= '-s '.(integer)$value.' ';
+                       break;
+                       case 'modulation':
+                       $shellcmd[$AdapterName] .= '-m '.$value.' ';
+                       break;
+                   case 'plp_id':
+                       $shellcmd[$AdapterName] .= '-9 '.(integer)$value.' ';
+                       break;
+                   case 'symbol_rate':
+                       $shellcmd[$AdapterName] .= '-s '.(integer)$value.' ';
+                       break;
+                   case 'out':
+                       $filecfgname = '/tmp/'.$AdapterName.'.dvbmcfg';
+                       $filecfgdata = implode("\n", $value)."\n";
+                       file_put_contents($filecfgname, $filecfgdata);
+                       $shellcmd[$AdapterName] .= '-c '.$filecfgname.' ';
+                       break;
+               }
+           }
+           $shellcmd[$AdapterName] .= $commonparams.'-q -r /tmp/dvb-'.$AdapterName.'.sock';
+       }
+       return $shellcmd;       
+    }
+}
+
+
+$PRG = new dvbmaster();
diff --git a/dvblastmaster/lib/mplib.php b/dvblastmaster/lib/mplib.php
new file mode 100644 (file)
index 0000000..871965c
--- /dev/null
@@ -0,0 +1,271 @@
+<?php\r
+\r
+/*\r
+ * VERSION 2.1b\r
+ */\r
+define('MPRole_PARENT', 0);\r
+define('MPRole_CHILD', 1);\r
+define('MPRole_ERROR', -1);\r
+\r
+class Daemon\r
+{\r
+    private static $unique_flag = FALSE;\r
+    private static $pidfilename;\r
+    \r
+    public static function shutdown()\r
+    {\r
+       if (self::$unique_flag)\r
+       {\r
+           @unlink(static::$pidfilename);\r
+       }\r
+       \r
+    }\r
+\r
+    public static function daemonize()\r
+    {\r
+       $pid = pcntl_fork();\r
+       if ($pid == -1)\r
+        {\r
+                return FALSE;\r
+        }\r
+        elseif ($pid > 0)\r
+        {\r
+            exit;\r
+        }\r
+       self::$origin_pid = posix_getpid();\r
+        umask(0);\r
+        chdir('/');\r
+        if (posix_setsid() == -1)\r
+        {\r
+           return FALSE;\r
+        }\r
+       \r
+       fclose(STDIN);\r
+       fclose(STDOUT);\r
+       fclose(STDERR);\r
+       $GLOBALS['STDIN'] = fopen('/dev/null', 'r');\r
+       $GLOBALS['STDOUT']= fopen('/dev/null', 'w');\r
+       $GLOBALS['STDERR'] = fopen('/dev/null', 'w');\r
+       \r
+       return TRUE;\r
+    }\r
+    \r
+    public static function is_unique($pidfilename)\r
+    {\r
+       $mypid = posix_getpid();\r
+       if (is_readable($pidfilename))\r
+       {\r
+           $pid = (int)  rtrim(file_get_contents($pidfilename));\r
+           if ($pid == $mypid)\r
+           {\r
+               return TRUE;\r
+           }\r
+           if ($pid > 0 && posix_kill($pid, 0))\r
+           {\r
+               return FALSE;\r
+           }\r
+       }\r
+       return TRUE;\r
+\r
+    }\r
+    \r
+    public static function no_unique($pidfilename)\r
+    {\r
+       if (!@unlink($pidfilename))\r
+       {\r
+           return FALSE;\r
+       }\r
+       else\r
+       {\r
+           return TRUE;\r
+       }\r
+    }\r
+\r
+    public static function do_unique($pidfilename)\r
+    {\r
+       if (!self::is_unique($pidfilename))\r
+       {\r
+           return FALSE;\r
+       }\r
+\r
+       $mypid = posix_getpid();\r
+       if (!@file_put_contents($pidfilename, $mypid.PHP_EOL))\r
+       {\r
+           return FALSE;\r
+       }\r
+       register_shutdown_function(['self','shutdown']);\r
+       return TRUE;\r
+    }\r
+}    \r
+\r
+abstract class Children \r
+{\r
+    protected $PIPE;\r
+    protected $ROLE;\r
+    protected static $CHILDREN;\r
+    protected $CHILD;\r
+    protected $PARENT;\r
+    protected $IPCRXBUFFER = [];\r
+\r
+\r
+    public function __construct($data = NULL)\r
+    {\r
+       self::set_sig_handlers();\r
+       $this->create_child();\r
+       switch ($this->ROLE)\r
+       {\r
+           case MPRole_ERROR:\r
+               return FALSE;\r
+           case MPRole_PARENT:\r
+               return TRUE;\r
+           case MPRole_CHILD:\r
+               $this->ChildBody($data);\r
+               exit();\r
+       }\r
+       \r
+    }\r
+    \r
+    public function __destruct()\r
+    {\r
+       if ($this->ROLE == MPRole_PARENT)\r
+       {\r
+           posix_kill($this->CHILD, SIGTERM);\r
+       }\r
+    }\r
+\r
+    abstract protected function ChildBody($data);\r
+\r
+    static function set_sig_handlers()\r
+    {\r
+       pcntl_signal(SIGCHLD, [__CLASS__, 'handler_sigchld']);\r
+    }\r
+    \r
+    public function SendUnixSignal($sig)\r
+    {\r
+       return posix_kill($this->CHILD, $sig);\r
+    }\r
+      \r
+    public function IsAlive()\r
+    {\r
+       if ($this->ROLE == MPRole_CHILD)\r
+       {\r
+           return TRUE;\r
+       }\r
+       if (isset(self::$CHILDREN[$this->CHILD]))\r
+       {\r
+           return TRUE;\r
+       }\r
+       else\r
+       {\r
+           return FALSE;\r
+       }\r
+    }\r
+\r
+    public static function handler_sigchld()\r
+    {  \r
+       $pid = pcntl_waitpid(0, $status, WNOHANG);\r
+       if($pid > 0 && isset(self::$CHILDREN[$pid]))\r
+       {\r
+           unset(self::$CHILDREN[$pid]);\r
+       }\r
+    }\r
+\r
+    protected function create_child()\r
+    {\r
+       $sockets = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);\r
+       stream_set_blocking ($sockets[0] , 0);\r
+       stream_set_blocking ($sockets[1] , 0);\r
+       $pid = pcntl_fork();\r
+       if ($pid == -1)\r
+       {\r
+           $this->ROLE = MPRole_ERROR;\r
+           return FALSE;\r
+       }\r
+       elseif ($pid > 0)\r
+       {\r
+           // код для родителя\r
+           $this->CHILD = $pid;\r
+           self::$CHILDREN[$pid] = $pid;\r
+           $this->PARENT = FALSE;\r
+           $this->ROLE = MPRole_PARENT;\r
+           $this->PIPE = &$sockets[0];\r
+           unset($sockets);\r
+           usleep(5000);\r
+       }\r
+       elseif ($pid == 0)\r
+       {\r
+           // код для ребёнка\r
+           $this->CHILD = FALSE;\r
+           $this->PARENT = posix_getppid();\r
+           $this->ROLE = MPRole_CHILD;\r
+           $this->PIPE = &$sockets[1];\r
+           unset($sockets);\r
+       }\r
+       return TRUE;\r
+    }\r
+    \r
+    public function SendEvent($eventname, $data)\r
+    {\r
+       if (!is_resource($this->PIPE))\r
+       {\r
+           return FALSE;\r
+       }\r
+       $eventpack = base64_encode($eventname).chr(255).chr(0).chr(255).base64_encode(serialize($data)).chr(0).chr(15).chr(240).chr(255);\r
+       \r
+       $res = @stream_socket_sendto($this->PIPE, $eventpack);  \r
+       if ($res == -1)\r
+       {\r
+           return TRUE;\r
+       }\r
+       else\r
+       {\r
+           return FALSE;\r
+       }\r
+    }\r
+    \r
+    public function WaitEvent($wait = TRUE)\r
+    {\r
+       if (count($this->IPCRXBUFFER) == 0)\r
+       {\r
+           if (!is_resource($this->PIPE))\r
+           {\r
+               return FALSE;\r
+           }\r
+\r
+           $r = [$this->PIPE];\r
+           if ($wait)\r
+           {\r
+               while (stream_select($r, $w, $x, 0) == 0)\r
+               {\r
+                   usleep(10000);\r
+                   $r = [$this->PIPE];\r
+               }\r
+           }\r
+           elseif (stream_select($r, $w, $x, 0) == 0)\r
+           {\r
+               return NULL;\r
+           }\r
+           $ipc_msg = '';\r
+           while (substr($ipc_msg , -4) != chr(0).chr(15).chr(240).chr(255))\r
+           {\r
+               $rcv_buf = stream_socket_recvfrom($this->PIPE, 1500);\r
+               if ($rcv_buf == '')\r
+               {\r
+                   return NULL;\r
+               }\r
+               $ipc_msg .= $rcv_buf;\r
+           }\r
+           $ipc_msg = explode(chr(0).chr(15).chr(240).chr(255), $ipc_msg);\r
+           array_pop($ipc_msg);\r
+           $this->IPCRXBUFFER = array_merge($this->IPCRXBUFFER, $ipc_msg);\r
+       }\r
+       $ipc_msg = array_shift($this->IPCRXBUFFER);\r
+       $ipc_msg = explode(chr(255).chr(0).chr(255), $ipc_msg);\r
+       \r
+       $retval['eventname'] = base64_decode($ipc_msg[0]);\r
+       $retval['data'] = unserialize(base64_decode($ipc_msg[1]));\r
+       \r
+       return $retval;\r
+       \r
+    }\r
+}\r
diff --git a/dvblastmaster/lib/sts.php b/dvblastmaster/lib/sts.php
new file mode 100644 (file)
index 0000000..9c7b8a5
--- /dev/null
@@ -0,0 +1,135 @@
+<?php
+
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+/**
+ * Description of inigen
+ *
+ * @author sleepy
+ */
+class STS
+{
+    private static $SigArray = FALSE;
+    private static $IsPrefixed = FALSE;
+    private static $IsLastEol;
+    private static $StdPrefix = '';
+
+    public static function generate_ini($ini_array)
+    {
+       if (!is_array($ini_array))
+       {
+           return FALSE;
+       }
+       if (count($ini_array) == 0)
+       {
+           return NULL;
+       }
+       $_RETVAL= '';
+       if (is_array($ini_array[key ($ini_array)]))
+       {
+           foreach ($ini_array as $sectionname => $sectiondata)
+           {
+               if(!is_array($sectiondata))
+               {
+                   return FALSE;
+               }
+               $_RETVAL .= '['.$sectionname.']'.PHP_EOL;
+               foreach ($sectiondata as $param => $data)
+               {
+                   if (is_array($data))
+                   {
+                       $data = '';
+                   }
+                   $_RETVAL .= $param.' = '.$data.PHP_EOL;
+               }
+               $_RETVAL .= PHP_EOL;
+           }
+       }
+       else
+       {
+           foreach ($ini_array as $param => $data)
+           {
+               $_RETVAL .= $param.' = '.$data.PHP_EOL;
+           }
+       }
+       return $_RETVAL;
+    }
+    private static function GetSignalDescription()
+    {
+       if (self::$SigArray === FALSE)
+       {
+           self::$SigArray = explode("\n", shell_exec('kill -l'));
+       }       
+    }
+    
+    public static function GetSignalMnemonicByNumber($signo)
+    {
+       self::GetSignalDescription();
+       if (isset(self::$SigArray[$signo]))
+       {
+           return self::$SigArray[$signo];
+       }
+       else
+       {
+           return FALSE;
+       }
+    }
+
+    public static function GetSignalNumberByMnemonic($sigmnemo)
+    {
+       self::GetSignalDescription();
+       return array_search($sigmnemo, self::$SigArray);
+    }
+
+    public static function stdout_prefix($prefix)
+    {
+       if (!self::$IsPrefixed)
+       {
+           self::$StdPrefix = $prefix;
+           ob_start(['self','ob_callback'],1);
+           self::$IsPrefixed = TRUE;
+           return TRUE;
+       }
+       else
+       {
+           return FALSE;
+       }
+
+    }
+
+    public static function stdout_unprefix()
+    {
+       if (self::$IsPrefixed)
+       {
+           ob_end_clean();
+           self::$IsPrefixed = FALSE;
+           return TRUE;
+       }
+       else
+       {
+           return FALSE;
+       }
+
+    }
+    
+    private static function ob_callback($buffer)
+    {
+       if (self::$IsLastEol)
+       {
+           $prefix = self::$StdPrefix;
+       }
+       else
+       {
+           $prefix = '';
+       }
+       self::$IsLastEol = substr($buffer, -1) == PHP_EOL;
+       return $prefix.$buffer;
+
+    }
+    
+}
+
diff --git a/dvblastmaster/lib/timer.php b/dvblastmaster/lib/timer.php
new file mode 100644 (file)
index 0000000..dc577cd
--- /dev/null
@@ -0,0 +1,119 @@
+<?php
+//VERSION 2.4
+register_tick_function(array('Timer','poll'));
+
+class Timer
+{
+    private $id; //метка
+    private $time; //таймер
+    private $IsStop = TRUE; //флаг остановленности true/false
+    private $UserCall; //задача
+    private $UserCallArg; //параметр к задаче в виде массива для передачи нескольких значений или единственного.
+    private $StartTime; //момент запуска таймера
+    private $ltime; //оставшееся время
+    private $type; //тип true регенерируемый, false не регенерируемый, null самоуничтожаемый не регенерируемый, применяется по умолчанию без присвоения, не может быть перезапущен.
+    private static $timers = []; 
+
+    public function __construct($time, $callable, $args = NULL,  $type = NULL) 
+    {
+       if ($args === NULL)
+       {
+           $args = [];
+       }
+       if (!is_array($args))
+       {
+           throw new Exception("parameter 3 must be an array, \$args=".gettype($args));
+       }
+       $this->id = uniqid();
+        $this->time = $time;
+        $this->UserCall = $callable;
+       $this->UserCallArg = $args;
+        $this->type = $type;
+       if (!is_callable($this->UserCall, TRUE, $callablename))
+       {
+           throw new Exception("parameter 2 must be callable, \$callable=". $callablename);
+       }
+       else
+       {    
+           $this->start();
+           self::$timers[$this->id] = &$this;
+       }
+    }
+
+    public function __destruct() 
+    {
+       unset(self::$timers[$this->id]);
+    }
+
+    private function getId()
+    {
+       return $this->id;
+    }
+
+    public function getTimeLeft()
+    {
+           return $this->ltime;
+    }
+
+    public function setTimeLeft($time)
+    {
+           $this->time = $time;
+    }
+
+
+    public function reset()
+    {
+       $this->StartTime = microtime(true);
+       $this->IsStop = FALSE;
+    }
+
+    public function start() 
+    {
+       $this->reset();
+       $this->IsStop = FALSE;
+    }
+
+    public function stop() 
+    {
+       $this->IsStop = TRUE;
+    }
+
+    public static function poll()
+    {
+       foreach (self::$timers as $timer)
+       {
+           if ($timer->IsStop == FALSE)
+           {
+               $timer->update();
+           }
+       }
+    }
+
+    private function update()
+    {
+       $this->ltime = $this->StartTime - microtime(true) + $this->time;
+       if ($this->ltime <= 0)
+       {
+           $this->ltime = 0;
+           $this->task();
+           if ($this->type === FALSE)
+           {
+               $this->stop();
+           }
+           elseif ($this->type === TRUE)
+           {
+               $this->reset();
+           }
+           elseif ($this->type === NULL)
+           {
+               $this->stop();
+               $this->__destruct();
+           }
+       }
+    }
+
+    private function task() 
+    {
+       call_user_func_array ($this->UserCall, $this->UserCallArg);
+    }
+}
diff --git a/dvblastmaster/sigtest.php b/dvblastmaster/sigtest.php
new file mode 100644 (file)
index 0000000..2fd38fc
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+$tarr1 = [1,2,3,4];
+$tarr2 = [1,2,3,4];
+$array1 = ['a' => 1, 'b' => 2, 'c' => $tarr1];
+$array2 = ['a' => 1, 'b' => 2, 'c' => $tarr2];
+//var_dump($tarr1 == $array2['c']);
+//var_dump($array1 == $array2);
+
+$result = array_udiff_assoc($array1, $array2,  function ($a, $b) {return (int)!($a === $b);});
+
+function cmpre($param1, $param2)
+{
+    var_dump($param1,$param2);
+    echo '------',PHP_EOL;
+    return 1;
+}
+
+var_dump($result);
+exit();
+var_dump($a);
+if (($a = 5) < 1)
+{
+    echo 'TRUE',PHP_EOL;
+}
+else
+{
+    echo 'FALSE',PHP_EOL;
+}
+var_dump($a);
+exit();
+// Обязательно
+declare(ticks = 1);
+
+// функция обработки сигнала
+function sig_handler($signo,$signinfo)
+{
+
+     
+    file_put_contents('/tmp/sigtest.txt', "PID:".posix_getpid()." GOT SIGNAL {$signo} ".print_r($signinfo,true)."\n", FILE_APPEND);
+     
+    
+
+}
+
+echo "Установка обработчиков сигналов...\n";
+
+// Установка обработчиков сигналов
+pcntl_signal(SIGTERM, "sig_handler");
+pcntl_signal(SIGHUP,  "sig_handler");
+pcntl_signal(SIGABRT, "sig_handler");
+pcntl_signal(SIGINT, "sig_handler");
+pcntl_signal(SIGQUIT, "sig_handler");
+pcntl_signal(SIGINT, "sig_handler");
+//pcntl_signal(SIGSTOP, "sig_handler");
+
+sleep(3);
+sleep(3);
+
+//exit();
+// или можете использовать объект
+// pcntl_signal(SIGUSR1, array($obj, "do_something"));
+
+while (1)
+{
+    echo '*';
+    sleep(1);
+}
\ No newline at end of file
diff --git a/term/lowterm.php b/term/lowterm.php
new file mode 100644 (file)
index 0000000..dfe7465
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+/**
+ * Description of lowterm
+ *
+ * @author sleepy
+ */
+class lowterm
+{
+    protected $terminfo;
+    
+    public function __construct()
+    {
+       
+    }
+}
diff --git a/term/testterm.php b/term/testterm.php
new file mode 100644 (file)
index 0000000..d5b1d81
--- /dev/null
@@ -0,0 +1,18 @@
+#!/usr/bin/env php
+<?php
+require_once 'lowterm.php';
+exec('infocmp -L -1', $output);
+unset($output[0],$output[1]);
+foreach ($output as $value)
+{
+   $kp = explode('=', rtrim(ltrim($value),','));
+   if (!isset($kp[1]))
+   {
+       $kp[1] = TRUE;
+   }
+   $attr[$kp[0]] = $kp[1];
+   
+}
+echo str_replace ('\E', chr(27), $attr["clear_screen"]);
+var_dump($attr);
+echo chr(27).'[425m';
\ No newline at end of file