Sloppy File Handling – Perl

When reading around the subject of file handling in Perl its easy to get sloppy, phrases like ‘automatic cleanup’ and the like lull us into believing that the close statement is just a ‘nice to have’. Well this burnt me today! I have a quick script to update our ‘Store and Forward’ mail servers, which reads from a database and then gets some output from a ┬átext file on another server, adds all the data into a hash, then produces a nice list in the form of a text file. A comparison is done with the production file and if needed it gets swapped out. Heres the (sanitised) script:

#! /usr/bin/perl -w

use strict;
use File::Compare;
use File::Copy;
use DBI;

my %domains;

# GET THE DOMAINS FROM THE MYSQL DB 

my $dbh = DBI->connect("DBI:mysql:XXXXXXX:XXXXX.XXXXXXX.XXX","XXXXXXXXXX","XXXXXXXXXXX", {RaiseError => 1}); 
my $sql="SELECT domain FROM XXXXXXX.mxstore ORDER BY domain";
my $sth = $dbh->prepare("$sql") or die "preparing: ", $dbh->errstr;
$sth->execute or die "executing: ", $dbh->errstr;
while(my ($domain)=$sth->fetchrow_array()) {
        $domains{$domain} = 1;
}

# Now get the domain list from the nameserver

if (my @mxlist=`ssh -l XXXXXXX XXX.XXXXX.XXX "grep 'XXXXXXXXXX' /etc/namedb/zones/*"`){
	foreach (@mxlist){
        	chomp;
		s/\/etc\/namedb\/zones\///;
		s/\.zone:.*$//;
        	$domains{$_} = 1;
	}

	open MX, "> /home/dan/tempmx.txt";
	for (sort keys %domains){
        	print MX "$_\n";
	}
	close MX;
	if (compare("/home/dan/tempmx.txt", "/etc/mail/relay-domains")){
		copy("/home/dan/tempmx.txt", "/etc/mail/relay-domains");
		system("kill -HUP `head -1 /var/run/sendmail.pid`");
		print "Updated\n";
	}

}
print "Completed\n";

What could possibly go wrong?

Well this version is the ‘fixed’ one which has the close MX; line in it, because without it it truncates the final file. Thats not strictly true, what is actually happening is that without the close the last bit of the list being printed to the MX filehandle has not been committed to the file/disk and so is not part of the file when the copy command is used. Of course when testing, prior to putting the compare and copy part in, all seems to be fine, because Perl ‘takes care of it’ when the program exits. In reality we were copying the file away before the program exit so the cleanup had not be done. We live and learn!

This entry was posted in FreeBSD Administration, MySQL, Perl and tagged , , , . Bookmark the permalink.

Leave a Reply