Re: lock files vs. non-predictable file names
by lhoward (Vicar) on Aug 26, 2000 at 00:59 UTC
|
Along the same lines as merlyn's suggestion; replace
the
system("/bin/rm $lock_file");
with
unlink($lock_file);
Again you're saving launching another process.
One algorithmic problem with your lockfile
approach is that if your process dies
(for whatever reason) without removing the
lockfile all subsequent runs of the program
will think there's already an instance running;
even though there isn't.
one last thing.... use strict.
Learn what it is and start using it. It will save you
much pain as you continue to learn and use perl. | [reply] [d/l] [select] |
|
|
Good point on the algorithmic problem. I inherited that functionality from the previous script, thinking about duplicate processes not premature death.
/me is reading up on strict.
ty
| [reply] |
Re: lock files vs. non-predictable file names
by merlyn (Sage) on Aug 26, 2000 at 00:57 UTC
|
Don't use /tmp for sentinel files like this. Create a directory writable only by the user running this crontab, and put the file in there. Then you won't have to worry about someone deleting your file.
Also, replace system touch.. with just
open DUH, ">/tmp/some.file";
close DUH;
No separate process required that way. Better security. Ditto with unlink instead of system rm.
And, you really don't want to use a sentinel file like that. See my Highlander - allow only one invocation at a time of an expensive CGI script
as a model to use flock with a sentinel file.
-- Randal L. Schwartz, Perl hacker | [reply] [d/l] |
|
|
Actually ">>/tmp/some.file" is better.
Opening the file by writing to it can lead to issues of
people, waiting for your process to start, then placing
a symlink to another file. It isn't easy and there is
definitely an element of luck, but keep trying and you
will hit it eventually. So create with an append, then
test for the symlink if you are paranoid.
Incidentally another model to look at for sentinal files is
Simple Locking.
| [reply] |
|
|
I was wondering about that (">" vs. ">>"). I actually got to learn about the symbolic link problem in /tmp through someone else's misfortune. Thanks for the link on Simple locking too.
| [reply] |
|
|
Thanks for advice on the private directory...and the replacements for the system calls. I think I'll devote some time to grok highlander...ty.
| [reply] |
Re: lock files vs. non-predictable file names
by Shendal (Hermit) on Aug 26, 2000 at 01:02 UTC
|
Firstly, I would question why you are using a lock file at all, as it wouldn't seem to matter to me if this runs a few times. At worst, you're getting a double page -- but that may not be such a bad thing.
Secondly, one way to make sure that your script created the lock file is to create a directory in temp, protected by your username (chmod 700), and create your lock file inside. When your script is finished, it can leave the dir, or delete it.
Other than that, the script looks fine to me. For only speaking perl for 5 days, it's quite good. You may want to look into the module Net::Ping on CPAN.
Cheers,
Shendal
| [reply] |
|
|
I thought about that too, why I was continuing to use the lock file that is. It was in the script I was trying to improve. I had asked someone familiar with the history of that script why it was being used, and they said somthing to the effect that at one time something prevented mailx from completing and reexecution of the script just caused more mailx instances and more script instances. But thinking about it as I type this, the $nlfile should prevent that problem from reoccuring, if it still exists.
I will dig into Net::Ping, so many modules-so little time.=)
Thanks for looking.
| [reply] |
Re: lock files vs. non-predictable file names
by JackHammer (Acolyte) on Aug 26, 2000 at 06:06 UTC
|
Probably isn't the answer you are looking for but if somebody is doing things such as touching lock files for your network monitoring script you should probably know about it anyway :) As far as I am concernced if the box you are using as a network monitoring station has malicious users on it you have bigger problems. If the file is there and isn't owned by you have it e-mail you... | [reply] |
|
|
That's a very good point. Since most of the boxen I use are "open", I'd like to make my scripts user proof...to prevent them from being a sort of "attractive nusance".
But I should certainly gather the info if a user does manage to impair the function of an admin script.
I think in its current form I will be sent email from cron if something fails, but I might add something in the script to send info on directory/file ownership if it fails.
| [reply] |
RE: lock files vs. non-predictable file names
by RuphSkunk (Acolyte) on Aug 26, 2000 at 05:50 UTC
|
Thank you monks for your wise and astute observations. I have included in my script that wisdom which fits with its purpose. Other wisdom is still being digested...(yummy).
The check_private_dir sub seems twisted and its only purpose it to make sure there is a protected dir to write to, if anyone can enlighten me with more elegant code, I'd be smarter for it (and thankfull).
UPDATE: I suppose I could create the private dir in /var/tmp, which on my systems is not cleared upon reboot, and I could remove all but one line from check_private_dir to test for the existance of the directory. However, I'd still be intersted in a cleaner way of executing the current check_private_dir for academic purposes.
#!/usr/bin/perl -w
# Run this perl code from cron every 5 minutes
# 0,5,10,15,20,25,30,35,40,45,50,55 * * * * /.ping_hosts.pl 2>&1
#
use strict;
use Net::Ping;
my $private_dir = "/tmp/ping_hosts_dir";
sub check_private_dir {
unless (-e $private_dir){ mkdir($private_dir, 0700) or die "Can't
+mkdir $private_dir\n" }
if (-d $private_dir) {
my $dec_mode = (stat($private_dir))[2];
my $oct_mode = sprintf "%lo", $dec_mode;
if (-O $private_dir and ($oct_mode == 40700)) { return }
elsif (-O $private_dir and ($oct_mode != 40700)) {
chmod(0700, $private_dir);
return;
}
else { die "We don't own the directory\n" }
}
else { die "$private_dir exists and is not a directory\n"; }
}
sub ping_hosts {
my $ws;
my $timeout = 2;
my @hosts = qw(host1 host2 host3 host4);
my $ping_obj = Net::Ping->new("icmp");
foreach $ws (@hosts) {
unless ($ping_obj->ping($ws, $timeout)) {
print "$ws did not respond to ping within the $timeout sec
+ond timeout period\n";
notify_admins($ws);
}
sleep(1); # To prevent flooding
}
$ping_obj->close(); # Redundant since open network conn is auto-cl
+osed when leaving sub
}
sub notify_admins { # Called from ping_hosts()
my $ws = shift(@_);
my $nfile = "${ws}.notify";
my $admins = "admin1\@mailhost.com, " .
"18005551212\@page.com, " .
"admin2\@mailhost.com, " .
"19005551212\@page.com";
unless (-e "${private_dir}/${nfile}") {
open(NOTIFY, ">>${private_dir}/${nfile}") or die "Can't create
+ notify file\n";
close(NOTIFY);
open(MAIL, "|mailx $admins") or die "Can't fork for mailx: $!\
+n";
print MAIL "$ws doesn't respond to ping\n";
close(MAIL);
}
}
### MAIN ###
check_private_dir();
ping_hosts();
| [reply] [d/l] |
|
|
This code scares me a bit:
my $oct_mode = sprintf "%lo", $dec_mode;
if (-O $private_dir and ($oct_mode == 40700)) { return }
elsif (-O $private_dir and ($oct_mode != 40700)) {
You are probably lucky that 40,700 decimal is a nice integer value. Why not
leave it at octal?
if (-O $private_dir and ($dec_mode == 040700)) { return }
elsif (-O $private_dir) {
And that value isn't really a "decimal" mode. It's the value of "the mode",
which usually prints out as decimal. Internally, it's binary, unless
you have a BCD-coded machine (not likely {grin}).
The other scary code here is your use of mailx. While the content
of your message cannot possibly contain a line that begins with tilde, you
might get complacent some day and permit such a line, and then you can say
buh-bye to security. Get in the right groove by looking at Mail::Mailer
pretty durn quick.
-- Randal L. Schwartz, Perl hacker | [reply] [d/l] [select] |
|
|
So, what you are trying to say is that perl stores the value that stat returns as a binary, but when I printed it out perl converted it to decimal. OK I think I got that now, but this other bit of code you left, I'm not sure I fully understand. Is that leading character a zero in 040700 and if so what does it do? presumably it causes an octal comparison?
I guess where I got the code I came up with was by
mkdir($private_dir, 0700);
$mode = (stat($private_dir))[2];
print "stat[2] returned $mode for a value\n"
the value returned was 16832 which clearly wasn't an octal value.
Could you explain to me a little bit about arbitrary base comparisons? I can't find any examples that I recognise. Also thank you for the bit o' wisdom on mailx, I didn't know it had that vunerability(sp). | [reply] [d/l] |
|
|
Ping host was Re: lock files vs. non-predictable file names
by RuphSkunk (Acolyte) on Dec 30, 2000 at 05:51 UTC
|
Here is the latest incarnation of this script. Many changes.
#!/usr/bin/perl -w
# Run this perl code from cron every 5 minutes
# Output from 'print' and 'die' will be sent to owner of the cron proc
+ess by cron.
use strict;
use Net::Ping;
use Net::SMTP;
my $private_dir = "/tmp/ping_hosts_dir";
sub check_private_dir { # Used to prevent notify files from being crea
+ted by non-superusers
unless (-e $private_dir){ mkdir($private_dir, 0700) or die "Can't
+mkdir $private_dir\n" }
if (-d $private_dir) {
my $mode = (stat($private_dir))[2];
if (-O $private_dir and ($mode == 040700)) { return }
elsif (-O $private_dir and ($mode != 040700)) {
chmod(0700, $private_dir);
return;
}
else { die "We don't own $private_dir\n" }
}
else { die "$private_dir exists and is not a directory\n"; }
}
sub ping_hosts {
my $ws;
my $alive;
my $count;
my $timeout = 3;
my @hosts = qw(host1 host2 host3 host4);
# Following uses perl module Net::Ping to prevent spawning externa
+l process
my $ping_obj = Net::Ping->new("icmp");
foreach $ws (@hosts) {
$alive = 0;
$count = 5;
while ($count > 0){
$alive += $ping_obj->ping($ws, $timeout);
last if ($alive);
$count--;
}
unless (-e "${private_dir}/${ws}.notify") {
unless ($alive) {
print "$ws did not respond to ping\n";
notify_admins($ws, "is_down");
}
}
elsif ($alive) {
print "$ws is back up\n";
notify_admins($ws, "is_up");
}
sleep(1); # To prevent flooding
}
$ping_obj->close(); # Redundant since open network conn is auto-cl
+osed when leaving sub
}
sub notify_admins { # Called from ping_hosts() with host and changed s
+tatus as arg
my $ws = shift(@_);
my $state = shift(@_);
my $nfile = "${private_dir}/${ws}.notify";
my @admins = qw(8005551212@page.metrocall.com 8885551212@page.metr
+ocall.com);
my $message;
if ( "$state" eq "is_down" ) {
# Following replaces system(touch $nfile) to prevent spawning
+external process
open(NOTIFY, ">>$nfile") or die "Can't create notify file\n";
close(NOTIFY);
$message = "$ws does not respond to ping\n";
}
else {
unlink ($nfile);
$message = "$ws is back up\n";
}
# Following replaces forking mailx to prevent spawning external pr
+ocess
# Note: Net::SMTP, part of the libnet collection of modules is not
+ part of standard pkg
my $smtp = Net::SMTP->new('mailhost', HELLO => 'corp.com') or die
+"Can't connect to mailhost for SMTP\n";
#$smtp->mail($ENV{USER}.'@corp.com');
$smtp->mail('root@corp.com');
$smtp->to(@admins);
$smtp->data($message);
$smtp->quit;
}
### MAIN ###
check_private_dir();
# Use $private_dir/hold.notify as a way of disabling notification durr
+ing controlled reboots
ping_hosts() unless (-e "$private_dir/hold.notify");
| [reply] [d/l] |