#!/usr/bin/perl use strict; use warnings; use POSIX ":sys_wait_h"; my %conf=( alarm_file => 'alarm.conf', deamon_pid_file => 'alarm.pid', alarm_list=>[], verbose=>0 ); #print join('|',@ARGV).' --- '.(grep{$_=~/--nofork/}@ARGV)."\n"; # run as deamon if(0 < grep{$_=~/--deamon/}@ARGV) { $conf{verbose}=1 if(0 < grep{$_=~/--verbose/}@ARGV); if(0 == grep{$_=~/--nofork/}@ARGV) { print "go to background.\n" if($conf{verbose}); exit if(fork); } # go to background print "save pid to file $conf{deamon_pid_file}\n" if($conf{verbose}); my $msg=save_pid($conf{deamon_pid_file}); die "$msg\n" if($msg); update_alarms(); # alarm_file neu laden wenn # das passende Signal über SysV-IPC # kommt $SIG{USR1}=\&update_alarms; while(1) { my $now=time(); # aufgelaufenen Alarme ausgeben... while( @{$conf{alarm_list}}>0 && $conf{alarm_list}->[0]->{time} < $now) { my $alarm=shift(@{$conf{alarm_list}}); print "ALARM! ".localtime($now)."\n"; print <<"EOF"; TITEL: $alarm->{title} INALT: $alarm->{message} EOF } # warte eine Sekunde sleep 1; } } # run as client else { my $title=''; my $time=0; my $message=''; for my $opt (@ARGV) { if($opt=~/--title=(.+)/) { $title=$1; } elsif($opt=~/--time=(.+)/) { $time=int($1); } elsif($opt=~/--message=(.+)/) { $message=$1; } elsif($opt=~/--verbose/) { $conf{verbose}=1; } else {die "Unknown option $opt\nusage:\n".usage();} } my $now=time(); if($now>=$time) { print "alarmdate not in the future!\n"; exit; } print "append alarm to file $conf{alarm_file}\n" if($conf{verbose}); my $msg=append_alarm($conf{alarm_file},$title,$time,$message); warn $msg."\n" if($msg); print "load deamon pid file from file $conf{deamon_pid_file}\n" if($conf{verbose}); my $pid; ($msg,$pid)=load_pid($conf{deamon_pid_file}); die $msg."\n" if($msg); if(waitpid($pid,WNOHANG)==-1) { print "old deamon pid file $conf{deamon_pid_file}. No demon running?\n" if($conf{verbose}); } else { print "sendig alarm update IPC signal to $pid\n" if($conf{verbose}); server_reload($pid); } } ################################# ######### FUNKTIONEN ############ ################################# sub usage { return <<"EOF"; $0 [--deamon | --title, --time, --message] --deamon : run as deamon --title : set title of alarmmessage --message : set alarmmessage --time : set time when the message ist displayed --verbose : be verbose --nofork : deamon don't fork and go to background EOF #' } ############## ### SERVER ### ############## sub save_pid { my $file=shift; open(my $fh, '>', $file) or return("Could not open $file ($!)"); print $fh $$; close($fh); return 0; } sub load_alarms { my $file=shift; my $now=time(); my @alarm_dates; my @msg; open(my $fh, '<', $file) or return(["Could not open $file ($!)"],[]); my $cnt=0; while(my $line = <$fh>) { $cnt++; chomp($line); # leere zeilen ignorieren; next if($line=~/^\s*$/); # kommentare ignorieren; next if($line=~/^\s*#/); # Zeile Parsen if($line=~/^\s*(.+?)\s*=\s*(\d+)\s*,\s*(.*?)$/) { my($title,$time,$message)=($1,$2,$3); push(@msg,"Alarm found in line $cnt"); #veraltete Alarme ignorieren if($time >= $now) { push( @alarm_dates, {title=>$title, time=>int($time), message=>$message} ); } else { push(@msg,"ignore old Alarm in Line $cnt"); } } else { push(@msg,"Could not parse Line $cnt !"); } } close($fh); return(\@msg,\@alarm_dates); } sub sort_alarms() { $conf{alarm_list}=[sort{$a->{time} <=> $b->{time}}@{$conf{alarm_list}}]; } sub update_alarms { print "load alarms from file $conf{alarm_file}\n" if($conf{verbose}); my ($msg,$alarm)=load_alarms($conf{alarm_file}); print join("\n",@$msg)."\n" if($conf{verbose}); $conf{alarm_list}=$alarm if(@$alarm >0); sort_alarms(); } ############## ### CLIENT ### ############## sub load_pid { my $file=shift; my $pid=0; open(my $fh, '<', $file) or return("Could not open $file ($!)",-1); $pid=int(<$fh>); close($fh); return('',$pid); } sub append_alarm { my $file=shift; my $title=shift; my $time=shift; my $message=shift; open(my $fh, '>>', $file) or return("Could not open $file ($!)"); print $fh "$title=$time,$message\n"; close($fh); return 0; } sub server_reload { my $deamon_pid=shift; kill('USR1',$deamon_pid); return 0; }