# * * * * * nice -n20 /root/bin/heat -s
use strict;
use warnings;
+my $schedulefile="/root/heat.schedule";
+my $statefile="/root/heat.state";
+my $resetfile="/root/heat.reset";
+my $usbrelay="/root/bin/usbrelay";
+my $logfile="/var/log/heat.log";
+require POSIX;
$|=1;
sub readfile($) {
my($fname)=@_;
close F or die "read-close $fname: $!";
return $F;
}
-sub writefile {
- my($fname,$content)=@_;
+sub writefile($$;$) {
+ my($fname,$content,$mode)=@_;
local *F;
- open F,">$fname" or die "$fname: $!";
+ open F,($mode||">").$fname or die "$fname: $!";
print F $content or die "write $fname: $!";
close F or die "write-close $fname: $!";
}
+sub logmsg($) {
+ my($s)=@_;
+ chomp $s;
+ writefile $logfile,POSIX::strftime("%Y-%m-%dT%H:%M:%S",localtime)." $s\n",">>";
+}
sub spawn($) {
my($cmd)=@_;
$cmd.=" >&2";
- system $cmd or return 1;
- warn "$cmd: $!";
- return 0;
+ system $cmd and die "$cmd: $!";
}
my($trash,$min,$hour)=localtime;
my $minutes=$hour*60+$min;
$minutes=$1*60+$2;
shift;
}
-my $schedulefile="/root/heat.schedule";
-my $statefile="/root/heat.state";
-my $resetfile="/root/heat.reset";
-my $usbrelay="/root/bin/usbrelay";
-my $schedule=readfile $schedulefile;
my $finishline;
my %schedule;
-while ($schedule=~s/^(0?(\d+):0?(\d+)) ([01s])\n//) {
- my $tm=$2*60+$3;
- warn "$schedulefile set twice for: $1" if defined $schedule{$tm};
- $schedule{$tm-24*60}="$1 $4\n";
- $schedule{$tm }="$1 $4\n";
- $schedule{$tm+24*60}="$1 $4\n";
-}
-warn "$schedulefile garbage: $schedule" if $schedule ne "";
+my $schedule;
+if (-e $schedulefile) {
+ $schedule=readfile $schedulefile;
+ while ($schedule=~s/^(0?(\d+):0?(\d+)) ([01s])\n//) {
+ my $tm=$2*60+$3;
+ warn "$schedulefile set twice for: $1" if defined $schedule{$tm};
+ $schedule{$tm-24*60}="$1 $4\n";
+ $schedule{$tm }="$1 $4\n";
+ $schedule{$tm+24*60}="$1 $4\n";
+ }
+ warn "$schedulefile garbage: $schedule" if $schedule ne "";
+ warn "Empty $schedulefile" if !%schedule;
+}
sub schedulenext($) {
+ return undef if !%schedule;
my($now)=@_;
my($bestprev,$prev,$bestnext,$next);
for my $found (keys(%schedule)) {
die "No bestnext" if !defined $bestnext;
return [$prev,$next];
}
-$finishline=schedulenext $minutes;
+$finishline=schedulenext($minutes);
+$finishline=[$finishline->[1]] if $finishline;
my $silent=shift if ($ARGV[0]||"") eq "-s";
+logmsg "command: ".join(" ",@ARGV) if !$silent&&@ARGV;
sub info($) {
my($s)=@_;
print $s if !$silent;
my $reset=readfile $resetfile if -e $resetfile;
my($resetminutes,$resetstate);
sub resetread() {
- $reset=~/^0?(\d+):0?(\d+) ([01s]|reset)\n$/ or warn "Invalid $resetfile: $reset";
+ $reset=~/^0?(\d+)[:.]0?(\d+) ([01s]|reset)\n$/ or warn "Invalid $resetfile: $reset";
$resetminutes=$1*60+$2;
$resetstate=($3 eq "reset"?undef:$3);
}
+sub unlink_resetfile() {
+ unlink $resetfile or die "$resetfile: $!";
+ logmsg "remove reset: $reset";
+ $reset=$resetminutes=undef;
+}
if (defined $reset) {
resetread;
- if ($resetminutes==$minutes) {
- unlink $resetfile or die "$resetfile: $!";
- $reset=$resetminutes=undef;
- }
+ unlink_resetfile if $resetminutes==$minutes;
}
sub finishlinereset() {
$finishline=schedulenext $resetminutes;
- splice @$finishline,1,0,$reset;
+ if ($finishline) {
+ $finishline=[$reset,$finishline->[1]];
+ } else {
+ $finishline=[$reset];
+ }
}
finishlinereset if defined $reset;
my $state=readfile $statefile;
chomp $state;
info $state;
my $newstate=shift;
-$newstate=$resetstate if !defined $newstate&&defined $resetstate&&!defined $resetminutes;
+if (!defined $newstate&&defined $resetstate&&!defined $resetminutes) {
+ $newstate=$resetstate;
+ logmsg "reset: $newstate";
+}
sub printminutes($) {
my($m)=@_;
return sprintf "%02d:%02d",int($m/60),$m%60;
}
if ($silent) {
- if (!defined $newstate&&!defined $reset) {
- my $prev=schedulenext($minutes)->[0];
- $newstate=$prev if $prev=~s{^@[ printminutes $minutes ] (.)\n$}{$1} or $prev=undef;
+ if (!defined $newstate&&!defined $reset&&%schedule) {
+ my $prev=schedulenext($minutes);
+ if ($prev) {
+ my $prev=$prev->[0];
+ if ($prev=~m{^@{[ printminutes $minutes ]} (.)\n$}) {
+ $newstate=$1;
+ logmsg "scheduled: $prev";
+ }
+ }
}
$newstate=$state if !defined $newstate;
}
die "state!={s|0|1}" if $newstate!~/^[s01]$/;
sub setstate() {
info "->$newstate";
+ writefile $statefile,"$newstate\n" if $state ne $newstate;
+ logmsg "$state->$newstate" if $state ne $newstate;
+ if ($newstate ne "s") {
+ my $pid=readfile "pidof -x dnf;true|";
+ die "\n".printminutes($minutes)." change $state".($state eq $newstate?"":"->$newstate")." refused: dnf running: $pid" if $pid;
+ }
my $both={"s"=>[0,0],"0"=>[1,0],"1"=>[1,1]}->{$newstate};
- $state eq $newstate or unlink $statefile or warn "$statefile: $!";
- ( spawn "$usbrelay 1 ".$both->[0]
- and spawn "$usbrelay 2 ".$both->[1])
- or do { unlink $statefile; die "usbrelay error"; };
- $state eq $newstate or writefile $statefile,"$newstate\n";
+ spawn "$usbrelay 1 ".$both->[0];
+ spawn "$usbrelay 2 ".$both->[1];
info "\n";
}
my $newreset=shift;
if (!defined $newreset) {
setstate;
if (!$silent&&defined $reset) {
- unlink $resetfile or die "$resetfile: $!";
- $finishline=schedulenext $minutes;
+ unlink_resetfile;
+ $finishline=schedulenext($minutes);
+ $finishline=[$finishline->[1]] if $finishline;
}
finish;
}
$reset=$newreset;
if ($reset=~/^\d+$/) {
- $resetminutes=$reset+$minutes;
+ $resetminutes=($reset+$minutes)%(24*60);
$reset=printminutes($resetminutes)." reset\n";
setstate;
} else {
- $reset.=" $newstate\n";
+ $reset.=" reset\n";
resetread;
+ $reset=printminutes($resetminutes)." $newstate\n";
info "\n";
}
writefile $resetfile,$reset;
+logmsg "new reset: $reset";
finishlinereset;
finish;