Заменить капли персонажей - PullRequest
0 голосов
/ 21 декабря 2011

У меня есть скрипт, который я использую, который проверяет IP-адрес, хранящийся в моем файле hosts.allow, на соответствие того, какой IP-адрес сопоставлен с моим именем хоста dyndns, чтобы я мог войти на свои серверы после того, как синхронизировал свой текущий IP-адрес с этим именем хоста. По какой-то причине, похоже, что скрипт вызывает действительно периодические проблемы.

в моем файле hosts.allow у меня есть такой раздел:

#SOme.gotdns.com
sshd : 192.168.0.1
#EOme.gotdns.com

#SOme2.gotdns.com
sshd : 192.168.0.2
#EOme2.gotdns.com

У меня есть скрипт, работающий на cron (каждую минуту), который выглядит так:

#!/usr/bin/php
<?php
$hosts = array('me.gotdns.com','me2.gotdns.com');
foreach($hosts as $host)
{
        $ip = gethostbyname($host);
        $replaceWith = "#SO".$host."\nsshd : ".$ip."\n#EO".$host;
        $filename = '/etc/hosts.allow';
        $handle = fopen($filename,'r');
        $contents = fread($handle, filesize($filename));
        fclose($handle);
        if (preg_match('/#SO'.$host.'(.*?)#EO'.$host.'/si', $contents, $regs))
        {
                $result = $regs[0];
        }
        if($result != $replaceWith)
        {
                $newcontents = str_replace($result,$replaceWith,$contents);
                $handle = fopen($filename,'w');
                if (fwrite($handle, $newcontents) === FALSE) {
                }
                fclose($handle);
        }
}
?>

Проблема, с которой я сталкиваюсь, заключается в том, что символы периодически удаляются (я предполагаю, что во время замены), что приводит к сбою будущих обновлений, когда он вставляет что-то вроде:

#SOme.gotdns.com
sshd : 192.168.0.1
#EOme.gotdn

обратите внимание на отсутствующий "s.com"

Это, конечно, означает, что я теряю доступ к серверу, есть идеи, почему это происходит?

Спасибо.

Ответы [ 3 ]

2 голосов
/ 21 декабря 2011

Это почти наверняка, потому что скрипт не завершил выполнение в течение одной минуты, прежде чем он снова запустится через cron.Вам нужно реализовать какую-то блокировку или использовать инструмент, который позволяет запускать только один экземпляр скрипта.Есть несколько инструментов, которые могут сделать это, например lockrun .

2 голосов
/ 21 декабря 2011

это может быть из-за времени выполнения скрипта - может быть слишком коротким - ИЛИ 1-минутный интервал слишком короткий. Пока cron выполняет эту работу, запускается другой процесс сценария, который может повлиять на первый.

1 голос
/ 21 декабря 2011

Я бы сказал, что для того, чтобы сделать это безопасно, вы должны получить эксклюзивную блокировку для файла в начале скрипта, прочитать все это в памяти один раз, изменить его в памяти, затем написатьэто обратно в файл в конце.Это также было бы значительно более эффективным с точки зрения дискового ввода-вывода.

Вы также должны изменить задание cron, чтобы оно выполнялось реже.Вероятно, причина, по которой у вас возникла эта проблема, заключается в том, что два процесса работают одновременно - блокируя файл, если это так, вы рискуете сложить процессы в ожидании получения блокировки.Настройка на каждые 5 минут должна быть достаточно хорошей - ваш IP не должен меняться , что часто!

Так что сделайте это ( FIXED ):

#!/usr/bin/php
<?php

  // Settings
  $hosts = array(
    'me.gotdns.com',
    'me2.gotdns.com'
  );
  $filename = '/etc/hosts.allow';

  // No time limit (shouldn't be necessary with CLI, but just in case)
  set_time_limit(0);

  // Open the file in read/write mode and lock it
  // flock() should block until it gets a lock
  if ((!$handle = fopen($filename, 'r+')) || !flock($handle, LOCK_EX)) exit(1);

  // Read the file
  if (($contents = fread($handle, filesize($filename)) === FALSE) exit(1);

  // Will be set to true if we actually make any changes to the file
  $changed = FALSE;

  // Loop hosts list
  foreach ($hosts as $host) {

    // Get current IP address of host
    if (($ip = gethostbyname($host)) == $host) continue;

    // Find the entry in the file
    $replaceWith = "#SO{$host}\nsshd : {$ip}\n#EO{$host}";
    if (preg_match("/#SO{$host}(.*?)#EO{$host}/si", $contents, $regs)) {
      // Only do this if there was a match - otherise risk overwriting previous
      // entries because you didn't reset the value of $result
      if ($regs[0] != $replaceWith) {
        $changed = TRUE;
        $contents = str_replace($regs[0], $replaceWith, $contents);
      }
    }

  }

  // We'll only change the contents of the file if the data changed
  if ($changed) {
    ftruncate($handle, 0); // Zero the length of the file
    rewind($handle); // start writing from the beginning
    fwrite($handle, $contents); // write the new data
  }

  flock($handle, LOCK_UN); // Unlock
  fclose($handle); // close
...