Developer
Developer

Reputation: 6350

Check if the file is in a open state in Perl

I have a Perl daemon which runs 24 X 7 and It is running something like this

my_program.pl > /logs/user/data.out

my_program.pl will write only in data.out file only when there is an error in the application, otherwise it will not write in it .

Now I am application which does the cleanup and check if the file is under /logs/user/ is 2 days old it deletes the file and it is not getting any error while deleting .

But the consequence of this is files being deleted and left in an open state which is causing Disk Space issue on the server.

Now what I am trying to do is to check in my cleanup program if the file is open don't delete it but i am not able to identify it as the cleanup application i have only filename and it's path .

I tried the suggestion given in the below links but nothing is helping me in that .

How do you check if a file is open using Perl? How can I check if a filehandle is open in Perl?

Could you please suggest how we can handle this condition in Perl

Upvotes: 1

Views: 372

Answers (2)

brian d foy
brian d foy

Reputation: 132802

Instead of redirecting to a file, I think you'd get better results of sending messages to syslogd (or whatever) and letting that take care of all of the details. Those things know how to cleanup and rotate files properly.

Upvotes: 2

DavidO
DavidO

Reputation: 13942

The problem is outside of Perl's control; you're using your shell's redirection to redirect STDOUT to a file, so from Perl's perspective writes are going to STDOUT; it didn't set up the redirection.

From within your Perl program you can ask if -t STDOUT to see if STDOUT has been redirected to a file or if it is a terminal. But that doesn't really capture whether that file is opened.

One way that would work would be to test lsof /logs/user/data.out. lsof is a shell utility, not a Perl function, so you would need to run it with backticks, qx, or similar. That will provide output of who has a claim on that file, including the PID. So with lsof you can determine if a file is opened, and who has it opened. If multiple entities have it opened, you'll see that too (try lsof /dev/null for example; lots of entities will have that opened).

If lsof doesn't return output for a file, that's because nobody has it opened.

Keep in mind, though, that if the redirection is set up externally to the script itself, it would be fragile to assume that the redirection never changes, by hard-coding that filename. It may be better to lsof based on username where the user matches the user that ran the script, and then find a file that matches expectations.

The lsof -u [UID or USERNAME] command would list only those files open by a specific user. You could combine that with $< to run against the script-running user:

my $lsof_output = `lsof -u $< $path`;

Then examine the output for files opened by the same pid: $$.

For completeness, I'll mention there's a Perl module on CPAN called Unix::Lsof which handles the details of parsing through lsof output for you.

Upvotes: 3

Related Questions