"Fossies" - the Fresh Open Source Software Archive

Member "fogproject-1.5.9/packages/web/lib/service/fogservice.class.php" (13 Sep 2020, 36538 Bytes) of package /linux/misc/fogproject-1.5.9.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "fogservice.class.php": 1.5.8_vs_1.5.9.

    1 <?php
    2 /**
    3  * Handles the fog linux services
    4  *
    5  * PHP version 5
    6  *
    7  * @category FOGService
    8  * @package  FOGProject
    9  * @author   Tom Elliott <tommygunsster@gmail.com>
   10  * @license  http://opensource.org/licenses/gpl-3.0 GPLv3
   11  * @link     https://fogproject.org
   12  */
   13 /**
   14  * Handles the fog linux services
   15  *
   16  * @category FOGService
   17  * @package  FOGProject
   18  * @author   Tom Elliott <tommygunsster@gmail.com>
   19  * @license  http://opensource.org/licenses/gpl-3.0 GPLv3
   20  * @link     https://fogproject.org
   21  */
   22 abstract class FOGService extends FOGBase
   23 {
   24     /**
   25      * The path for the log
   26      *
   27      * @var string
   28      */
   29     public static $logpath = '';
   30     /**
   31      * Device (tty) to output to
   32      *
   33      * @var string
   34      */
   35     public static $dev = '';
   36     /**
   37      * The log file name.
   38      *
   39      * @var string
   40      */
   41     public static $log = '';
   42     /**
   43      * Sleep time
   44      *
   45      * @var int
   46      */
   47     public static $zzz = '';
   48     /**
   49      * Process references
   50      *
   51      * @var array
   52      */
   53     public $procRef = array();
   54     /**
   55      * Process pipes
   56      *
   57      * @var array
   58      */
   59     public $procPipes = array();
   60     /**
   61      * Node IPs we have in the database to check in service startup
   62      *
   63      * @var array
   64      */
   65     public static $knownips = array();
   66     /**
   67      * Initializes the FOGService class
   68      *
   69      * @return void
   70      */
   71     public function __construct()
   72     {
   73         parent::__construct();
   74         $logpath = trim(trim(self::getSetting('SERVICE_LOG_PATH'), '/'));
   75         if (!$logpath) {
   76             $logpath = 'opt/fog/log';
   77         }
   78         self::$logpath = sprintf(
   79             '/%s/',
   80             $logpath
   81         );
   82         Route::listem(
   83             'storagenode',
   84             'name',
   85             false,
   86             [ 'isEnabled' => [1] ]
   87         );
   88         $StorageNodes = json_decode(
   89             Route::getData()
   90         )->storagenodes;
   91         foreach ((array)$StorageNodes as &$StorageNode) {
   92             self::$knownips[] = $StorageNode->ip;
   93         }
   94     }
   95     /**
   96      * Checks if the node runnning this is indeed the master
   97      *
   98      * @return array
   99      */
  100     protected function checkIfNodeMaster()
  101     {
  102         self::getIPAddress();
  103         $find = [
  104             'isMaster' => [1],
  105             'isEnabled' => [1]
  106         ];
  107         Route::listem(
  108             'storagenode',
  109             'name',
  110             false,
  111             $find
  112         );
  113         $StorageNodes = json_decode(
  114             Route::getData()
  115         );
  116         $StorageNodes = $StorageNodes->storagenodes;
  117         foreach ((array)$StorageNodes as &$StorageNode) {
  118             $ip = self::resolveHostname(
  119                 $StorageNode->ip
  120             );
  121             if (!in_array($ip, self::$ips)) {
  122                 continue;
  123             }
  124             $MasterIDs[] = $StorageNode->id;
  125         }
  126         $StorageNodes = self::getClass('StorageNodeManager')->find(
  127             ['id' => $MasterIDs]
  128         );
  129         self::$HookManager->processEvent(
  130             'CHECK_NODE_MASTERS',
  131             array(
  132                 'StorageNodes' => $StorageNodes,
  133                 'FOGServiceClass' => &$this,
  134                 'MasterIDs' => &$MasterIDs
  135             )
  136         );
  137         if (count($StorageNodes) > 0) {
  138             return $StorageNodes;
  139         }
  140         throw new Exception(
  141             _(' | This is not the master node')
  142         );
  143     }
  144     /**
  145      * Wait to ensure the network interface is ready
  146      *
  147      * @return void
  148      */
  149     public function waitInterfaceReady()
  150     {
  151         self::getIPAddress(true);
  152         if (!count(self::$ips) || !array_intersect(self::$knownips, self::$ips)) {
  153             self::outall(
  154                 sprintf(
  155                     '%s: %s',
  156                     _('Interface not ready, waiting for it to come up'),
  157                     self::getSetting('FOG_WEB_HOST')
  158                 )
  159             );
  160             sleep(10);
  161             $this->waitInterfaceReady();
  162             return;
  163         }
  164         foreach (self::$ips as &$ip) {
  165             self::outall(
  166                 _("Interface Ready with IP Address: $ip")
  167             );
  168             unset($ip);
  169         }
  170     }
  171     /**
  172      * Wait to ensure the DB is ready
  173      *
  174      * @return void
  175      */
  176     public function waitDbReady()
  177     {
  178         if (DatabaseManager::getLink()) {
  179             return;
  180         }
  181         self::outall(
  182             sprintf(
  183                 'FOGService: %s - %s',
  184                 get_class($this),
  185                 _('Waiting for mysql to be available')
  186             )
  187         );
  188         sleep(10);
  189         $this->waitDbReady();
  190     }
  191     /**
  192      * Displays the banner for fog services
  193      *
  194      * @return void
  195      */
  196     public function getBanner()
  197     {
  198         ob_start();
  199         echo "\n";
  200         echo "==================================\n";
  201         echo "===        ====    =====      ====\n";
  202         echo "===  =========  ==  ===   ==   ===\n";
  203         echo "===  ========  ====  ==  ====  ===\n";
  204         echo "===  ========  ====  ==  =========\n";
  205         echo "===      ====  ====  ==  =========\n";
  206         echo "===  ========  ====  ==  ===   ===\n";
  207         echo "===  ========  ====  ==  ====  ===\n";
  208         echo "===  =========  ==  ===   ==   ===\n";
  209         echo "===  ==========    =====      ====\n";
  210         echo "==================================\n";
  211         echo "===== Free Opensource Ghost ======\n";
  212         echo "==================================\n";
  213         echo "============ Credits =============\n";
  214         echo "= https://fogproject.org/Credits =\n";
  215         echo "==================================\n";
  216         echo "== Released under GPL Version 3 ==\n";
  217         echo "==================================\n";
  218         echo "\n";
  219         self::outall(ob_get_clean());
  220     }
  221     /**
  222      * Outputs the string passed
  223      *
  224      * @param string $string the string to output
  225      *
  226      * @return void
  227      */
  228     public function outall($string)
  229     {
  230         self::wlog("$string\n", static::$log);
  231         return;
  232     }
  233     /**
  234      * Get's the current datetime
  235      *
  236      * @return string
  237      */
  238     protected static function getDateTime()
  239     {
  240         return self::niceDate()->format('m-d-y g:i:s a');
  241     }
  242     /**
  243      * Outputs the passed string to the log
  244      *
  245      * @param string $string the string to write to log
  246      * @param string $path   the log path to write to
  247      *
  248      * @return void
  249      */
  250     protected static function wlog($string, $path)
  251     {
  252         if (file_exists($path)) {
  253             $filesize = (double)self::getFilesize($path);
  254             $max_size = (double)self::getSetting('SERVICE_LOG_SIZE');
  255             if (!$max_size) {
  256                 $max_size = 500000;
  257             }
  258             if ($filesize >= $max_size) {
  259                 unlink($path);
  260             }
  261         }
  262         $fh = fopen($path, 'ab');
  263         if (!$fh) {
  264             return;
  265         }
  266         fwrite(
  267             $fh,
  268             sprintf(
  269                 '[%s] %s',
  270                 self::getDateTime(),
  271                 $string
  272             )
  273         );
  274         fclose($fh);
  275     }
  276     /**
  277      * Attempts to start the service
  278      *
  279      * @return void
  280      */
  281     public function serviceStart()
  282     {
  283         self::outall(
  284             sprintf(
  285                 ' * Starting %s Service',
  286                 get_class($this)
  287             )
  288         );
  289         self::outall(
  290             sprintf(
  291                 ' * Checking for new items every %s seconds',
  292                 static::$zzz
  293             )
  294         );
  295         self::outall(' * Starting service loop');
  296         return;
  297     }
  298     /**
  299      * Runs the service
  300      *
  301      * @return void
  302      */
  303     public function serviceRun()
  304     {
  305         $this->waitDbReady();
  306         $tmpTime = self::getSetting(static::$sleeptime);
  307         if (static::$zzz != $tmpTime) {
  308             static::$zzz = $tmpTime;
  309             self::outall(
  310                 sprintf(
  311                     " | Sleep time has changed to %s seconds",
  312                     static::$zzz
  313                 )
  314             );
  315         }
  316     }
  317     /**
  318      * Replicates data without having to keep repeating
  319      *
  320      * @param int    $myStorageGroupID this servers groupid
  321      * @param int    $myStorageNodeID  this servers nodeid
  322      * @param object $Obj              that is trying to send data
  323      * @param bool   $master           master->master or master->nodes
  324      * @param mixed  $fileOverride     file override.
  325      *
  326      * @return void
  327      */
  328     protected function replicateItems(
  329         $myStorageGroupID,
  330         $myStorageNodeID,
  331         $Obj,
  332         $master = false,
  333         $fileOverride = false
  334     ) {
  335         $itemType = $master ? 'group' : 'node';
  336         $groupID = $myStorageGroupID;
  337         if ($master) {
  338             $groupID = $Obj->get('storagegroups');
  339         }
  340         $find = [
  341             'isEnabled' => 1,
  342             'storagegroupID' => $groupID
  343         ];
  344         if ($master) {
  345             $find['isMaster'] = [1];
  346         }
  347         Route::indiv(
  348             'storagenode',
  349             $myStorageNodeID
  350         );
  351         $myStorageNode = json_decode(
  352             Route::getData()
  353         );
  354         if (!$myStorageNode->isMaster) {
  355             throw new Exception(
  356                 _('This is not the master for this group')
  357             );
  358         }
  359         if (!$myStorageNode->online) {
  360             throw new Exception(
  361                 _('This node does not appear to be online')
  362             );
  363         }
  364         Route::listem(
  365             'storagenode',
  366             'name',
  367             false,
  368             $find
  369         );
  370         $StorageNodes = json_decode(
  371             Route::getData()
  372         );
  373         $StorageNodes = $StorageNodes->storagenodes;
  374         $objType = get_class($Obj);
  375         $groupOrNodeCount = count($StorageNodes ?: []);
  376         $counttest = 2;
  377         if (!$master) {
  378             $groupOrNodeCount--;
  379             $counttest = 1;
  380         }
  381         if ($groupOrNodeCount < $counttest) {
  382             self::outall(
  383                 sprintf(
  384                     ' * %s %s %s %s',
  385                     _('Not syncing'),
  386                     $objType,
  387                     _('between'),
  388                     _("{$itemType}s")
  389                 )
  390             );
  391             self::outall(
  392                 sprintf(
  393                     ' | %s %s: %s',
  394                     $objType,
  395                     _('Name'),
  396                     $Obj->get('name')
  397                 )
  398             );
  399             self::outall(
  400                 sprintf(
  401                     ' | %s.',
  402                     _('There are no other members to sync to')
  403                 )
  404             );
  405         } else {
  406             self::outall(
  407                 sprintf(
  408                     ' * %s %s %s %s %s',
  409                     _('Found'),
  410                     _($objType),
  411                     _('to transfer to'),
  412                     $groupOrNodeCount,
  413                     (
  414                         $groupOrNodeCount != 1 ?
  415                         _("{$itemType}s") :
  416                         _($itemType)
  417                     )
  418                 )
  419             );
  420             self::outall(
  421                 sprintf(
  422                     ' | %s %s: %s',
  423                     $fileOverride ? _('File') : _($objType),
  424                     _('Name'),
  425                     $fileOverride ?: $Obj->get('name')
  426                 )
  427             );
  428             $getPathOfItemField = 'ftppath';
  429             $getFileOfItemField = 'path';
  430             if ($objType == 'Snapin') {
  431                 $getPathOfItemField = 'snapinpath';
  432                 $getFileOfItemField = 'file';
  433             }
  434             $myDir = sprintf(
  435                 '/%s/',
  436                 trim($myStorageNode->{$getPathOfItemField}, '/')
  437             );
  438             if (false === $fileOverride) {
  439                 $myFile = basename($Obj->get($getFileOfItemField));
  440             } else {
  441                 $myFile = $fileOverride;
  442             }
  443             $myAdd = "$myDir$myFile";
  444             $myAddItem = false;
  445             foreach ($StorageNodes as $i => &$StorageNode) {
  446                 if ($StorageNode->id == $myStorageNodeID) {
  447                     continue;
  448                 }
  449                 if (!$StorageNode->online) {
  450                     self::outall(
  451                         sprintf(
  452                             ' | %s server does not appear to be online.',
  453                             $StorageNode->name
  454                         )
  455                     );
  456                     continue;
  457                 }
  458                 $groupID = $StorageNode->storagegroupID;
  459                 if ($master
  460                     && $groupID == $myStorageGroupID
  461                 ) {
  462                     continue;
  463                 }
  464                 if ($fileOverride) {
  465                     $name = $fileOverride;
  466                     $randind = "abcdef$i";
  467                 } else {
  468                     $name = $Obj->get('name');
  469                     $randind = $i;
  470                 }
  471                 if (isset($this->procRef[$itemType])
  472                     && isset($this->procRef[$itemType][$name])
  473                     && isset($this->procRef[$itemType][$name][$randind])
  474                 ) {
  475                     $isRunning = $this->isRunning(
  476                         $this->procRef[$itemType][$name][$randind]
  477                     );
  478                     if ($isRunning) {
  479                         self::outall(
  480                             sprintf(
  481                                 '| %s: %d',
  482                                 _('Replication already running with PID'),
  483                                 $this->getPID(
  484                                     $this->procRef[$itemType][$name][$randind]
  485                                 )
  486                             )
  487                         );
  488                         continue;
  489                     }
  490                 }
  491                 if (!file_exists($myAdd)
  492                     || !is_readable($myAdd)
  493                 ) {
  494                     self::outall(
  495                         sprintf(
  496                             ' * %s %s %s %s',
  497                             _('Not syncing'),
  498                             $objType,
  499                             _('between'),
  500                             _("{$itemType}s")
  501                         )
  502                     );
  503                     self::outall(
  504                         sprintf(
  505                             ' | %s %s: %s',
  506                             $fileOverride ? _('File') : _($objType),
  507                             _('Name'),
  508                             $name
  509                         )
  510                     );
  511                     self::outall(
  512                         sprintf(
  513                             ' | %s.',
  514                             _('File or path cannot be reached')
  515                         )
  516                     );
  517                     continue;
  518                 }
  519                 $testip = $StorageNode->ip;
  520                 $sizeurl = sprintf('%s://%s/fog/status/getsize.php', self::$httpproto, $testip);
  521                 $hashurl = sprintf('%s://%s/fog/status/gethash.php', self::$httpproto, $testip);
  522                 self::$FOGFTP
  523                     ->set('username', $StorageNode->user)
  524                     ->set('password', $StorageNode->pass)
  525                     ->set('host', $StorageNode->ip);
  526                 if (!self::$FOGFTP->connect()) {
  527                     self::outall(
  528                         sprintf(
  529                             ' * %s %s',
  530                             _('Cannot connect to'),
  531                             $StorageNode->name
  532                         )
  533                     );
  534                     continue;
  535                 }
  536                 $nodename = $StorageNode->name;
  537                 $username = self::$FOGFTP->get('username');
  538                 $password = self::$FOGFTP->get('password');
  539                 $ip = self::$FOGFTP->get('host');
  540                 $encpassword = urlencode($password);
  541                 $removeDir = sprintf(
  542                     '/%s/',
  543                     trim(
  544                         $StorageNode->{$getPathOfItemField},
  545                         '/'
  546                     )
  547                 );
  548                 $removeFile = $myFile;
  549                 $limitmain = self::byteconvert(
  550                     $myStorageNode->bandwidth
  551                 );
  552                 $limitsend = self::byteconvert(
  553                     $StorageNode->bandwidth
  554                 );
  555                 $limitset = "";
  556                 if ($limitmain > 0) {
  557                     $limitset = "set net:limit-total-rate 0:$limitmain;";
  558                 }
  559                 if ($limitsend > 0) {
  560                     $limitset .= "set net:limit-rate 0:$limitsend;";
  561                 }
  562                 unset($limit);
  563                 $limit = $limitset;
  564                 unset($limitset);
  565                 unset($remItem);
  566                 unset($includeFile);
  567                 $ftpstart = "ftp://$username:$encpassword@$ip";
  568                 if (is_file($myAdd)) {
  569                     $remItem = dirname("$removeDir$removeFile");
  570                     $path = $remItem;
  571                     $removeFile = basename($removeFile);
  572                     $opts = '-R -i';
  573                     $includeFile = basename($myFile);
  574                     if (!$myAddItem) {
  575                         $myAddItem = dirname($myAdd);
  576                     }
  577                     $localfilescheck[0] = $myAdd;
  578                     if (file_exists($ftpstart.$remItem."/".$removeFile)) {
  579                         $remotefilescheck[0] = sprintf(
  580                             '%s/%s',
  581                             $remItem,
  582                             $removeFile
  583                         );
  584                     }
  585                 } elseif (is_dir($myAdd)) {
  586                     $remItem = "$removeDir$removeFile";
  587                     $path = realpath($myAdd);
  588                     $localfilescheck = self::globrecursive(
  589                         "$path/**{,.}*[!.,!..]",
  590                         GLOB_BRACE
  591                     );
  592                     $remotefilescheck = self::$FOGFTP->listrecursive($remItem);
  593                     $opts = '-R';
  594                     $includeFile = '';
  595                     if (!$myAddItem) {
  596                         $myAddItem = $myAdd;
  597                     }
  598                 }
  599                 $localfilescheck = array_values(
  600                     array_filter(
  601                         array_unique($localfilescheck)
  602                     )
  603                 );
  604                 foreach ($localfilescheck as &$lfn) {
  605                     $lfn = str_replace("$path/", "", $lfn);
  606                     unset($lfn);
  607                 }
  608                 $remotefilescheck = array_values(
  609                     array_filter(
  610                         array_unique($remotefilescheck)
  611                     )
  612                 );
  613                 foreach ($remotefilescheck as &$rfn) {
  614                     $rfn = str_replace("$remItem/", "", $rfn);
  615                     unset($rfn);
  616                 }
  617                 $filescheck = array_unique(array_merge((array)$localfilescheck, (array)$remotefilescheck));
  618                 $testavail = -1;
  619                 $allsynced = true;
  620 
  621                 $resp = self::$FOGURLRequests->isAvailable($testip, 1, 80);
  622                 $avail = true;
  623                 $testavail = array_filter($resp);
  624                 $testavail = array_shift($testavail);
  625                 if (!$testavail) {
  626                     $avail = false;
  627                 }
  628 
  629                 foreach ($filescheck as $j => &$filename) {
  630                     $filesequal = false;
  631                     $lindex = array_search($filename, $localfilescheck);
  632                     $rindex = array_search($filename, $remotefilescheck);
  633                     $localfilename = sprintf('%s%s%s', $path, "/", $localfilescheck[$lindex]);
  634                     $remotefilename = sprintf('%s%s%s', $remItem, "/", $remotefilescheck[$rindex]);
  635                     if (!is_int($rindex)) {
  636                         $allsynced = false;
  637                         self::outall(sprintf(
  638                             '  # %s: %s %s (%s)',
  639                             $name,
  640                             _('File does not exist'),
  641                             $filename,
  642                             $nodename
  643                         ));
  644                     } elseif (!is_int($lindex)) {
  645                         self::outall(sprintf(
  646                             '  # %s: %s %s %s %s %s',
  647                             $name,
  648                             _('File does not exist'),
  649                             'on master node, deleting',
  650                             $filename,
  651                             'on',
  652                             $nodename
  653                         ));
  654                         self::$FOGFTP->delete($remotefilename);
  655                     } else {
  656                         $localsize = self::getFilesize($localfilename);
  657                         $remotesize = null;
  658                         if ($avail) {
  659                             $rsize = self::$FOGURLRequests->process(
  660                                 $sizeurl,
  661                                 'POST',
  662                                 ['file' => base64_encode($remotefilename)]
  663                             );
  664                             $rsize = array_shift($rsize);
  665                             if (is_int($rsize)) {
  666                                 $remotesize = $rsize;
  667                             } else {
  668                                 // we should re-try HTTPS because we don't know about the storage node setup
  669                                 // and letting curl follow the redirect doesn't work for POST requests
  670                                 $sizeurl = sprintf('%s://%s/fog/status/getsize.php', 'https', $testip);
  671                                 $rsize = self::$FOGURLRequests->process(
  672                                     $sizeurl,
  673                                     'POST',
  674                                     ['file' => base64_encode($remotefilename)]
  675                                 );
  676                                 $rsize = array_shift($rsize);
  677                                 if (is_int($rsize)) {
  678                                     $remotesize = $rsize;
  679                                 }
  680                             }
  681                         }
  682                         if (is_null($remotesize)) {
  683                             $remotesize = self::$FOGFTP->size($remotefilename);
  684                         }
  685                         if ($localsize == $remotesize) {
  686                             $localhash = self::getHash($localfilename);
  687                             $remotehash = null;
  688                             if ($avail) {
  689                                 $rhash = self::$FOGURLRequests->process(
  690                                     $hashurl,
  691                                     'POST',
  692                                     ['file' => base64_encode($remotefilename)]
  693                                 );
  694                                 $rhash = array_shift($rhash);
  695                                 if (strlen($rhash) == 64) {
  696                                     $remotehash = $rhash;
  697                                 } else {
  698                                     // we should re-try HTTPS because we don't know about the storage node setup
  699                                     // and letting curl follow the redirect doesn't work for POST requests
  700                                     $hashurl = sprintf('%s://%s/fog/status/gethash.php', 'https', $testip);
  701                                     $rhash = self::$FOGURLRequests->process(
  702                                         $hashurl,
  703                                         'POST',
  704                                         ['file' => base64_encode($remotefilename)]
  705                                     );
  706                                     $rhash = array_shift($rhash);
  707                                     if (strlen($rhash) == 64) {
  708                                         $remotehash = $rhash;
  709                                     }
  710                                 }
  711                             }
  712                             if (is_null($remotehash)) {
  713                                 if ($localsize < 10485760) {
  714                                     $remotehash = hash_file('sha256', $ftpstart.$remotefilename);
  715                                 } else {
  716                                     $filesequal = true;
  717                                 }
  718                             }
  719                             if ($localhash == $remotehash) {
  720                                 $filesequal = true;
  721                             } else {
  722                                 self::outall(sprintf(
  723                                     '  # %s: %s - %s: %s != %s',
  724                                     $name,
  725                                     _('File hash mismatch'),
  726                                     $filename,
  727                                     $localhash,
  728                                     $remotehash
  729                                 ));
  730                             }
  731                         } else {
  732                             self::outall(sprintf(
  733                                 '  # %s: %s - %s: %s != %s',
  734                                 $name,
  735                                 _('File size mismatch'),
  736                                 $filename,
  737                                 $localsize,
  738                                 $remotesize
  739                             ));
  740                         }
  741                         if ($filesequal != true) {
  742                             $allsynced = false;
  743                             self::outall(sprintf('  # %s: %s %s', $name, _('Deleting remote file'), $filename));
  744                             self::$FOGFTP->delete($remotefilename);
  745                         } else {
  746                             self::outall(sprintf(
  747                                 '  # %s: %s %s (%s)',
  748                                 $name,
  749                                 _('No need to sync'),
  750                                 $filename,
  751                                 $nodename
  752                             ));
  753                             continue;
  754                         }
  755                     }
  756                     unset($filename);
  757                 }
  758                 self::$FOGFTP->close();
  759                 if ($allsynced) {
  760                     self::outall(' * ' . _('All files synced for this item.'));
  761                     continue;
  762                 }
  763                 $logname = sprintf(
  764                     '%s.%s.transfer.%s.log',
  765                     rtrim(
  766                         substr(
  767                             static::$log,
  768                             0,
  769                             -4
  770                         ),
  771                         '.'
  772                     ),
  773                     $Obj->get('name'),
  774                     $nodename
  775                 );
  776                 if (!$i) {
  777                     self::outall(
  778                         sprintf(
  779                             ' * %s',
  780                             _('Starting Sync Actions')
  781                         )
  782                     );
  783                 }
  784                 $this->killTasking(
  785                     $randind,
  786                     $itemType,
  787                     $name
  788                 );
  789                 $myAddItem = escapeshellarg($myAddItem);
  790                 $remItem = escapeshellarg($remItem);
  791                 $logname = escapeshellarg($logname);
  792                 $myAddItem = trim($myAddItem, "'");
  793                 $myAddItem = sprintf(
  794                     '"%s"',
  795                     $myAddItem
  796                 );
  797                 $remItem = trim($remItem, "'");
  798                 $remItem = sprintf(
  799                     '"%s"',
  800                     $remItem
  801                 );
  802                 $logname = trim($logname, "'");
  803                 $cmd = "lftp -e 'set xfer:log 1; set xfer:log-file $logname;";
  804                 $cmd .= "set ftp:list-options -a;set net:max-retries ";
  805                 $cmd .= "10;set net:timeout 30; $limit mirror -c --parallel=20 ";
  806                 $cmd .= "$opts ";
  807                 if (!empty($includeFile)) {
  808                     $includeFile = escapeshellarg($includeFile);
  809                     $includeFile = trim($includeFile, "'");
  810                     $includeFile = sprintf(
  811                         '"%s"',
  812                         $includeFile
  813                     );
  814                     $cmd .= "$includeFile ";
  815                 }
  816                 $cmd .= "--ignore-time -vvv --exclude \".srvprivate\" ";
  817                 $cmd .= "$myAddItem $remItem;";
  818                 $cmd2 = sprintf(
  819                     "%s exit' -u $username,[Protected] $ip",
  820                     $cmd
  821                 );
  822                 $cmd .= "exit' -u $username,'$password' $ip";
  823                 self::outall(" | CMD: $cmd2");
  824                 unset($includeFile, $remItem, $myAddItem);
  825                 $this->startTasking(
  826                     $cmd,
  827                     $logname,
  828                     $randind,
  829                     $itemType,
  830                     $name
  831                 );
  832                 self::outall(
  833                     sprintf(
  834                         ' | %s %s %s - %s',
  835                         _('Started sync for'),
  836                         $objType,
  837                         $name,
  838                         print_r($this->procRef[$itemType][$name][$randind], true)
  839                     )
  840                 );
  841                 unset($StorageNode);
  842             }
  843         }
  844     }
  845     /**
  846      * Starts taskings
  847      *
  848      * @param string $cmd      The command to start
  849      * @param string $logname  The name of the log to write to
  850      * @param int    $index    The index to store tasking reference
  851      * @param mixed  $itemType The type of the item
  852      * @param mixed  $filename Filename extra
  853      *
  854      * @return void
  855      */
  856     public function startTasking(
  857         $cmd,
  858         $logname,
  859         $index = 0,
  860         $itemType = false,
  861         $filename = false
  862     ) {
  863         if (isset($this->altLog)) {
  864             $log = $this->altLog;
  865         } else {
  866             $log = static::$log;
  867         }
  868         self::wlog(_('Task started'), $logname);
  869         $descriptor = array(
  870             0 => array('pipe', 'r'),
  871             2 => array('file', $log, 'a')
  872         );
  873         if ($itemType === false) {
  874             $this->procRef[$index] = proc_open(
  875                 $cmd,
  876                 $descriptor,
  877                 $pipes
  878             );
  879             $this->procPipes[$index] = $pipes;
  880         } else {
  881             $this->procRef[$itemType][$filename][$index] = proc_open(
  882                 $cmd,
  883                 $descriptor,
  884                 $pipes
  885             );
  886             $this->procPipes[$itemType][$filename][$index] = $pipes;
  887         }
  888     }
  889     /**
  890      * Kills all child processes
  891      *
  892      * @param int   $pid the pid to scan
  893      * @param mixed $sig the signal to kill with
  894      *
  895      * @return void
  896      */
  897     public function killAll($pid, $sig)
  898     {
  899         exec("ps -ef|awk '\$3 == '$pid' {print \$2}'", $output, $ret);
  900         if ($ret) {
  901             return false;
  902         }
  903         while (list(, $t) = each($output)) {
  904             if ($t != $pid) {
  905                 $this->killAll($t, $sig);
  906             }
  907         }
  908         posix_kill($pid, $sig);
  909     }
  910     /**
  911      * Kills the tasking
  912      *
  913      * @param int    $index    the index for the item to look into
  914      * @param mixed  $itemType the type of the item
  915      * @param string $filename the filename to close out
  916      *
  917      * @return bool
  918      */
  919     public function killTasking(
  920         $index = 0,
  921         $itemType = false,
  922         $filename = false
  923     ) {
  924         if ($itemType === false) {
  925             foreach ((array)$this->procPipes[$index] as $i => &$close) {
  926                 fclose($close);
  927                 unset($close);
  928             }
  929             unset($this->procPipes[$index]);
  930             if ($this->isRunning($this->procRef[$index])) {
  931                 $pid = $this->getPID($this->procRef[$index]);
  932                 if ($pid) {
  933                     $this->killAll($pid, SIGTERM);
  934                 }
  935                 proc_terminate($this->procRef[$index], SIGTERM);
  936                 proc_close($this->procRef[$index]);
  937                 return (bool)$this->isRunning($this->procRef[$index]);
  938             } elseif ($this->isRunning($this->procRef)) {
  939                 $pid = $this->getPID($this->procRef);
  940                 if ($pid) {
  941                     $this->killAll($pid, SIGTERM);
  942                 }
  943                 proc_terminate($this->procRef, SIGTERM);
  944                 proc_close($this->procRef);
  945                 return (bool)$this->isRunning($this->procRef);
  946             }
  947         } else {
  948             if (isset($this->procRef[$itemType]) &&
  949                 isset($this->procRef[$itemType][$filename]) &&
  950                 isset($this->procRef[$itemType][$filename][$index])
  951             ) {
  952                 $procRef = $this->procRef[$itemType][$filename][$index];
  953             } else {
  954                 return true;
  955             }
  956             if (isset($this->procPipes[$itemType]) &&
  957                 isset($this->procPipes[$itemType][$filename]) &&
  958                 isset($this->procPipes[$itemType][$filename][$index])
  959             ) {
  960                 $pipes = $this->procPipes[$itemType][$filename][$index];
  961             } else {
  962                 return true;
  963             }
  964             $isRunning = $this->isRunning(
  965                 $procRef
  966             );
  967             if ($isRunning) {
  968                 $pid = $this->getPID(
  969                     $procRef
  970                 );
  971                 if ($pid) {
  972                     $this->killAll($pid, SIGTERM);
  973                 }
  974                 proc_terminate($procRef, SIGTERM);
  975             } else {
  976                 return true;
  977             }
  978             proc_close($procRef);
  979             foreach ((array)$pipes as $i => &$close) {
  980                 fclose($close);
  981                 unset($close);
  982             }
  983             unset($pipes);
  984             return (bool)$this->isRunning(
  985                 $procRef
  986             );
  987         }
  988     }
  989     /**
  990      * Gets the pid of the running reference
  991      *
  992      * @param resouce $procRef the reference to check
  993      *
  994      * @return int
  995      */
  996     public function getPID($procRef)
  997     {
  998         if (!$procRef) {
  999             return false;
 1000         }
 1001         $ar = proc_get_status($procRef);
 1002         return $ar['pid'];
 1003     }
 1004     /**
 1005      * Checks if the passed reference is still running
 1006      *
 1007      * @param resource $procRef the reference to check
 1008      *
 1009      * @return bool
 1010      */
 1011     public function isRunning($procRef)
 1012     {
 1013         if (!$procRef) {
 1014             return false;
 1015         }
 1016         $ar = proc_get_status($procRef);
 1017         return $ar['running'];
 1018     }
 1019     /**
 1020      * Local file glob recursive getter.
 1021      *
 1022      * @param string $pattern a Pattern for globbing onto.
 1023      * @param mixed  $flags   any required flags.
 1024      *
 1025      * @return array
 1026      */
 1027     public static function globrecursive(
 1028         $pattern,
 1029         $flags = 0
 1030     ) {
 1031         $files = glob($pattern, $flags);
 1032         foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as &$dir) {
 1033             $files = array_merge(
 1034                 (array)$files,
 1035                 self::globrecursive(
 1036                     $dir . '/' . basename($pattern),
 1037                     $flags
 1038                 )
 1039             );
 1040             unset($file);
 1041         }
 1042         return $files;
 1043     }
 1044     /**
 1045      * Local file glob recursive getter.
 1046      *
 1047      * @return array
 1048      */
 1049     public function cleanupProcList()
 1050     {
 1051         foreach ($this->procRef as $item => &$itemTypes) {
 1052             foreach ($itemTypes as $image => &$images) {
 1053                 foreach ($images as $i => &$ref) {
 1054                     if (!$this->isRunning($images[$i])) {
 1055                         self::outall(" | Sync finished - " . print_r($images[$i], true));
 1056                         fclose($this->procPipes[$item][$image][$i]);
 1057                         unset($this->procPipes[$item][$image][$i]);
 1058                         fclose($images[$i]);
 1059                         unset($images[$i]);
 1060                     }
 1061                 }
 1062                 if (!count($itemTypes[$image])) {
 1063                     unset($itemTypes[$image]);
 1064                 }
 1065                 if (!count($this->procPipes[$item][$image])) {
 1066                     unset($this->procPipes[$item][$image]);
 1067                 }
 1068             }
 1069             if (!count($this->procRef[$item])) {
 1070                 unset($this->procRef[$item]);
 1071             }
 1072             if (!count($this->procPipes[$item])) {
 1073                 unset($this->procPipes[$item]);
 1074             }
 1075         }
 1076     }
 1077 }