2011-12-21 5 views
0

내 hosts.allow 파일에 저장된 IP 주소를 확인하는 데 사용하는 스크립트가 있습니다. 내 IP를 내 dynndns 호스트 이름에 매핑하면 내 서버에 로그인 할 수 있습니다. 호스트 이름. 어떤 이유로 스크립트가 실제로 간헐적 인 문제를 일으키는 것으로 보입니다.방울 문자 교체

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

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

내가 스크립트 크론에서 실행이 (분당) 다음과 같습니다 :

#!/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); 
     } 
} 
?> 

문제를 내 hosts.allow에 파일 내에서

나는이 같은 섹션이 나는 그 간헐적으로 문자가 떨어지고있다 (나는 교체하는 동안 가정한다)는 다음과 같은 것을 삽입 할 때 실패 할 미래의 업데이트를 일으킨다 :

물론 이것은 내가 서버에 액세스 할 수 없게 의미

"s.com"실종210

노트, 어떤 아이디어가 왜 이런 일이 일어나고 있을까?

감사합니다.

+1

입니까? – RageZ

+0

첫 번째 인스턴스가 완료되기 전에 다시 실행되는 동일한 스크립트를 의미합니까? – robjmills

+0

예 스크립트가 읽기 및 쓰기에 동일한 파일을 사용하고 있으므로 두 프로세스가 동시에 실행되면 재미있는 결과가 발생할 수 있습니다. – RageZ

답변

1

이 작업을 안전하게 수행하려면 스크립트 시작 부분의 파일에 acquire an exclusive lock을 적어두고 메모리에 한 번 읽고 메모리에 수정 한 다음 끝에 파일에 다시 씁니다. . 디스크 I/O 측면에서도 상당히 효율적입니다.

자주 실행되지 않도록 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 
+0

나를 위해 몇 가지 새로운 기능. 이 고맙습니다. – robjmills

2

스크립트 실행 시간 때문일 수 있습니다. 너무 짧거나 1 분 간격이 너무 짧습니다. cron이 작업을 수행하는 동안 스크립트의 다른 프로세스가 시작되고 첫 번째 프로세스에 영향을 미칠 수 있습니다.

+0

'스크립트 실행 시간으로 인한 것일 수 있습니다 .' - CLI에 문제가 없어야하며 시간 제한은 웹 요청에만 적용되어야합니다. 하나 이상의 인스턴스 가능성을 막기 위해 파일을 잠그고 있어야합니다. – DaveRandom

2

스크립트가 cron을 통해 다시 시작되기 전에 1 분 내에 실행을 완료하지 않았기 때문에 거의 확실합니다. 어떤 종류의 잠금을 구현하거나 스크립트 인스턴스를 한 번만 실행할 수있는 도구를 사용해야합니다. 이를 수행 할 수있는 몇 가지 도구가 있습니다 (예 : lockrun).