#! /usr/local/bin/php -c /usr/local/etc/php.ini "; $DB = "host=pgsql74.hub.org port=5432 dbname=186_www user=186_pgsql"; $dt = getdate(); $today = $dt['year'] . "-" . $dt['mon'] . "-" . $dt['mday']; $LOG = "PostgreSQL.org mirror check script starting at " . $dt['hours'] . ":" . $dt['minutes'] . ":" . $dt['seconds'] . "...\n\n"; if ($NOTIFY_ADMINS == 0) { $LOG .= "Note: Administrator notification emails will NOT be sent.\n\n"; } // Check for old temp files, and bleat if we cannot remove them if (file_exists("/tmp/checkmirrors.sync_timestamp") == true) { if (@unlink("/tmp/checkmirrors.sync_timestamp") == false) { $LOG .= "FATAL ERROR: Couldn't delete old tmp file: \"/tmp/checkmirrors.sync_timestamp\""; mail($EMAIL, "PostgreSQL mirror test report (FATAL ERROR): " . $today, $LOG, "From: webmaster@postgresql.org\nReply-To: webmaster@postgresql.org"); exit; } } // Check connectivity $LOG .= "Checking Internet connectivity..."; $fp = @fsockopen("www.google.com", 80, $errno1, $errstr1); if (!$fp) { $fp = @fsockopen("www.yahoo.com", 80, $errno2, $errstr2); if (!$fp) { $LOG .= "Couldn't connect to the test sites:\n\n"; $LOG .= "www.google.com - Error: " . $errno1 . "; " . $errstr1 . "\n"; $LOG .= "www.yahoo.com - Error: " . $errno2 . "; " . $errstr2 . "!\n\n"; mail($EMAIL, "PostgreSQL mirror test report: " . $today, $LOG, "From: webmaster@postgresql.org\nReply-To: webmaster@postgresql.org"); exit; } } @fclose($fp); $LOG .= "Done.\n\n"; // connect to database $LOG .= "Connecting to database..."; $db = @pg_pconnect($DB); if ($php_errormsg != "") { $LOG .= "Couldn't connect to the database server: " . $DB . "\n\n" . $php_errormsg; mail($EMAIL, "PostgreSQL mirror test report: " . $today, $LOG, "From: webmaster@postgresql.org\nReply-To: webmaster@postgresql.org"); exit; } $LOG .= "Done.\n\n"; // // FTP Mirrors // $LOG .= "\nChecking FTP mirrors:\n\n"; $sql = "SELECT * FROM mirrors WHERE mirror_type = 'ftp' AND mirror_active = TRUE ORDER BY country_code, mirror_index;"; $rs = @pg_exec($db, $sql); if (pg_result_status($rs) != PGSQL_TUPLES_OK && pg_result_status($rs) != PGSQL_COMMAND_OK) { $LOG .= "Error: Could not query the mirrors table!\n\n" . $php_errormsg; mail($EMAIL, "PostgreSQL mirror test report: " . $today, $LOG, "From: webmaster@postgresql.org\nReply-To: webmaster@postgresql.org"); exit; } $rows = pg_numrows($rs); for ($x = 0; $x < $rows; $x++) { $idx = pg_result($rs, $x, "mirror_index"); if ($idx == 0) $idx = ""; $port = ":". pg_result($rs, $x, "host_port"); if ($port = ":") $port = ""; if (pg_result($rs, $x, "host_use_cname") == 'f') $path = pg_result($rs, $x, "host_addr") . $port . pg_result($rs, $x, "host_path"); else $path = pg_result($rs, $x, "host_cname_host") . $port . pg_result($rs, $x, "host_path"); $host = "ftp" . $idx . "." . pg_result($rs, $x, "country_code") . ".postgresql.org"; $LOG .= "Testing: " . $host . ":\n"; // DNS Check $LOG .= " DNS: " . dns_check($db, pg_result($rs, $x, "id"), $host) . "\n"; // Sync check $sync = ftp_check($db, pg_result($rs, $x, "id"), $path, $idx, pg_result($rs, $x, "country_code")); $LOG .= " Sync: " . $sync . "\n"; // Error count if (substr($sync, 0, 5) == "ERROR") { $errcount = intval(pg_result($rs, $x, "error_count") + 1); $LOG .= " Error count: " . $errcount . "\n"; // Send an error email to the admin if required. $admin = pg_result($rs, $x, "host_email"); if ($errcount == 3) { if ($NOTIFY_ADMINS == 1) { message1($host, $admin, $sync); $LOG .= " *** 3 error warning message sent to administrator ***\n\n"; } } else if ($errcount == 15) { if ($NOTIFY_ADMINS == 1) { message2($host, $admin, $sync); $LOG .= " *** 15 error warning message sent to administrator ***\n\n"; } } else if ($errcount == 30) { if ($NOTIFY_ADMINS == 1) { message3($host, $admin, $sync); } pg_exec($db, "DELETE FROM mirrors WHERE id = " . pg_result($rs, $x, "id")); $LOG .= " *** MIRROR DELETED ***\n\n"; } else { $LOG .= "\n"; } } else { $LOG .= " Error count: 0\n\n"; } } $dt = getdate(); $LOG .= "\nCompleted at " . $dt['hours'] . ":" . $dt['minutes'] . ":" . $dt['seconds'] . "."; mail($EMAIL, "PostgreSQL mirror test report: " . $today, $LOG, "From: webmaster@postgresql.org\nReply-To: webmaster@postgresql.org"); pg_close($db); // // Check a DNS entry // $db is a database connection // $id is the mirrors ID number in the dabatase // $host is a hostname to check // function dns_check($db, $id, $host) { $res = checkdnsrr($host, "A"); if ($res) { pg_exec($db, "UPDATE mirrors SET mirror_dns = TRUE WHERE id = " . $id); return "'A' record -> " . gethostbyname($host) . " found"; } $res = checkdnsrr($host, "CNAME"); if ($res) { pg_exec($db, "UPDATE mirrors SET mirror_dns = TRUE WHERE id = " . $id); return "'CNAME' record found"; } pg_exec($db, "UPDATE mirrors SET mirror_dns = FALSE WHERE id = " . $id); return "ERROR: NO DNS RECORD"; } // // Check an FTP mirror // $db is a database connection // $id is the mirrors ID number in the dabatase // $path is a full is a hostname and path to the sync_timestamp file, using the hosts IP or CNAME // $idx is the mirror index, or blank for zero // $country is the country code // function ftp_check($db, $id, $path, $idx, $country) { $url = "ftp://" . $path; $url_stuff = parse_url($url); $conn = @ftp_connect($url_stuff['host']); if (!$conn) { pg_exec($db, "UPDATE mirrors SET error_count = (error_count + 1) WHERE id = " . $id); return "ERROR - Host not found"; } @ftp_set_option($conn, FTP_TIMEOUT_SEC, 15); $login = ftp_login($conn, "anonymous", "webmaster@postgresql.org"); if (!$login) { pg_exec($db, "UPDATE mirrors SET error_count = (error_count + 1) WHERE id = " . $id); return "ERROR - Login failed"; } // Attempt to switch to PASV mode. Don't complain if this should fail @ftp_pasv($conn, TRUE); if ($url_stuff['path'] != "") { if (!ftp_chdir($conn, $url_stuff['path'])) { pg_exec($db, "UPDATE mirrors SET error_count = (error_count + 1) WHERE id = " . $id); return "ERROR - Directory not found"; } } if (!@ftp_get($conn, "/tmp/checkmirrors.sync_timestamp", "sync_timestamp", FTP_BINARY)) { pg_exec($db, "UPDATE mirrors SET error_count = (error_count + 1) WHERE id = " . $id); return "ERROR - File not found"; } ftp_close($conn); $fp = fopen("/tmp/checkmirrors.sync_timestamp", "r"); $buffer = ''; while ($tmp = fread($fp, 1024)) { $buffer .= $tmp; } $sync = substr($buffer, 0, 23); fclose($fp); @unlink("/tmp/checkmirrors.sync_timestamp"); // Check for a valid timestamp if (($timestamp = strtotime($sync)) === -1) { pg_exec($db, "UPDATE mirrors SET error_count = (error_count + 1) WHERE id = " . $id); return "ERROR - Invalid timestamp retrieved: " . $sync; } // Check for stale content $age = date_diff($timestamp, mktime()); if (intval($age['days']) >= 2) { pg_exec($db, "UPDATE mirrors SET error_count = (error_count + 1), mirror_last_rsync = '" . $sync . "' WHERE id = " . $id); return "ERROR - Stale content: generated at " . $sync; } // Now check for http connectivity $http = 0; $http_root = 0; if (fetch_http($url_stuff['host'], $url_stuff['path'] . '/sync_timestamp', 'ftp' . $idx . '.' . $country . '.postgresql.org')) { $http = 1; } else { if (fetch_http($url_stuff['host'], '/sync_timestamp', 'ftp' . $idx . '.' . $country . '.postgresql.org')) { $http = 1; $http_root = 1; } } // Looking good :-) pg_exec($db, "UPDATE mirrors SET error_count = 0, mirror_last_rsync = '" . $sync . "', alternate_protocol=$http::boolean, alternate_at_root=$http_root::boolean WHERE id = " . $id); $httpstr = $http?"Yes":"No"; return $sync . "\n HTTP: $httpstr"; } function fetch_http($host, $url, $hostheader) { $s = @fsockopen($host, 80); if ($s) { @socket_set_timeout($s, 10); $g = "GET " . $url . " HTTP/1.0\nHost: " . $hostheader . "\nUser-Agent: pgMirrorCheck/0.1\n\n"; fwrite($s, $g); $line = fgets($s); if (preg_match('@HTTP/(\d\.\d)\s*(\d+)@', $line, $matches)) { if ($matches[2] == 200) { // HTTP/200. Now check if we got a valid sync_timestamp while ($line = fgets($s)) { if ($line == "\r\n") { $line = fgets($s); if ($line) { // Have a line, check the timestamp $timestamp = strtotime($line); if ($timestamp) { $age = date_diff($timestamp, mktime()); if (intval($age['days']) < 2) { // We have a valid timestamp! fclose($s); return 1; } } } break; } } } } fclose($s); } return 0; } // // Send a first warning email // $mirror is the mirror hostname // $email is the email address to send to // $error is the error message returned // function message1($mirror, $email, $error) { $msg = ' You have been sent this email because you are listed as the administrative contact for the PostgreSQL.org mirror site above. If this is incorrect, please email webmaster@postgresql.org, quoting the mirror hostname, and discard this message. The PostgreSQL mirror network is monitored daily to ensure that all mirrors are functioning correctly and serving up to date content. This email has been automatically generated because three consecutive errors have been detected when checking your mirror. The error returned was: ' . $error . ' The check works by looking for file called sync_timestamp in the root directory of the mirrored content. If errors such as \'File Not Found\' are seen, this may indicate that the incorrect content is being served, or the ftp base directory is not what we have recorded. Other errors may be caused by the maximum user limit being consistently reached, or virtual host configuration problems on web mirrors. Please correct the problem if you are able, or contact webmaster@postgresql.org if you are unsure what the problem is, how to resolve it, or if you need your mirror to be temporarily marked inactive. If the problem remains unresolved, a further email will be sent when the error count reaches fifteen, and the mirror details will be deleted should the error count reach thirty. Regards, The PostgreSQL MirrorBot. '; mail($email, "PostgreSQL mirror: " . $mirror, $msg, "From: webmaster@postgresql.org\nReply-To: webmaster@postgresql.org"); } // // Send a second warning email // $mirror is the mirror hostname // $email is the email address to send to // $error is the error message returned // function message2($mirror, $email, $error) { $msg = ' You have been sent this email because you are listed as the administrative contact for the PostgreSQL.org mirror site above. If this is incorrect, please email webmaster@postgresql.org, quoting the mirror hostname, and discard this message. The PostgreSQL mirror network is monitored daily to ensure that all mirrors are functioning correctly and serving up to date content. This email has been automatically generated because fifteen consecutive errors have been detected when checking your mirror. The error returned was: ' . $error . ' The check works by looking for file called sync_timestamp in the root directory of the mirrored content. If errors such as \'File Not Found\' are seen, this may indicate that the incorrect content is being served, or the ftp base directory is not what we have recorded. Other errors may be caused by the maximum user limit being consistently reached, or virtual host configuration problems on web mirrors. Please correct the problem if you are able, or contact webmaster@postgresql.org if you are unsure what the problem is, how to resolve it, or if you need your mirror to be temporarily marked inactive. This is the second email advising you of this problem that has been sent. If the problem remains unresolved, the mirror details will be deleted when the error count reaches thirty. Regards, The PostgreSQL MirrorBot. '; mail($email, "PostgreSQL mirror: " . $mirror, $msg, "From: webmaster@postgresql.org\nReply-To: webmaster@postgresql.org"); } // // Send a mirror deleted email // $mirror is the mirror hostname // $email is the email address to send to // $error is the error message returned // function message3($mirror, $email, $error) { $msg = ' You have been sent this email because you are listed as the administrative contact for the PostgreSQL.org mirror site above. If this is incorrect, please email webmaster@postgresql.org, quoting the mirror hostname, and discard this message. The PostgreSQL mirror network is monitored daily to ensure that all mirrors are functioning correctly and serving up to date content. This email has been automatically generated because thirty consecutive errors have been detected when checking your mirror. The error returned was: ' . $error . ' The check works by looking for file called sync_timestamp in the root directory of the mirrored content. If errors such as \'File Not Found\' are seen, this may indicate that the incorrect content is being served, or the ftp base directory is not what we have recorded. Other errors may be caused by the maximum user limit being consistently reached, or virtual host configuration problems on web mirrors. This is the third email that has been sent regarding this problem, and as it has not yet been resolved the mirror details have been deleted from our database. Should you wish to start mirroring the site again in the future, please contact webmaster@postgresql.org. ` Regards, The PostgreSQL MirrorBot. '; mail($email, "PostgreSQL mirror: " . $mirror, $msg, "From: webmaster@postgresql.org\nReply-To: webmaster@postgresql.org"); } // // Returns the d/h/m/s difference between 2 dates // Lifted from the PHP user docs example by scott_webster_2000 at yahoo dot com // $earlierDate is the earliest date // $laterDate is the later date // function date_diff($earlierDate, $laterDate) { $ret=array('days'=>0,'hours'=>0,'minutes'=>0,'seconds'=>0); $totalsec = $laterDate - $earlierDate; if ($totalsec >= 86400) { $ret['days'] = floor($totalsec/86400); $totalsec = $totalsec % 86400; } if ($totalsec >= 3600) { $ret['hours'] = floor($totalsec/3600); $totalsec = $totalsec % 3600; } if ($totalsec >= 60) { $ret['minutes'] = floor($totalsec/60); } $ret['seconds'] = $totalsec % 60; return $ret; } ?>