#!/usr/bin/perl

use strict;
use warnings;
use IO::File;
use Fcntl qw(:flock);
use POSIX qw(setsid);
use Getopt::Long;
use vars qw($opt_start $opt_stop $opt_status $opt_restart);

my $uid = $<; $< = $>;

if ($uid != 0) {
    print "$0 must be run under root account!\n";
    exit 1;
}

$| = 1;

GetOptions("start" => \$opt_start,
            "stop" => \$opt_stop,
            "status" => \$opt_status,
            "restart" => \$opt_restart) || usage('no args');

if ($opt_start)   { daemonize(); };
if ($opt_start)   { apps_start(); exit 0; };
if ($opt_stop)    { apps_stop('1'); };
if ($opt_status)  { apps_status(); };
if ($opt_restart) { apps_stop('0'); daemonize(); apps_start(); exit 0;};

usage('no args');

sub usage {
    my $mes = shift;
    logging("$mes");
    print "usage $mes\n";
    print "OPTIONS: --start --stop --status --restart\n";
    exit 1;
}

sub daemonize {
    my $pidfile = '/var/run/machpause.pid';
    if (-f $pidfile) {
	logging("PID-File $pidfile found, deamon running.");
        print "PID-File $pidfile found, deamon running!\n";
        exit 1;
    }
    chdir '/' or die "Can't chdir to /: $!\n";
    open STDIN, '/dev/null' or die "Can't read /dev/null: $!\n";
    open STDOUT, '>>/dev/null' or die "Can't write to /dev/null: $!\n";
    open STDERR, '>>/dev/null' or die "Can't write to /dev/null: $!\n";
    defined (my $pid = fork) or die "Can't fork: $!\n";
    if ($pid) {
        my $fh = IO::File->new(">$pidfile") or die "Can't open $pidfile: $!\n";
        if ($fh) {
            print $fh $pid;
            $fh->close();
        }
        exit 0;
    }
    setsid or die "Can't start a new session: $!\n";
    umask 0;
}

sub apps_start {
    $SIG{'TERM'} = sub { logging("terminated by (SIGTERM)"); exit 0;};
    $SIG{'INT'} = sub { logging("terminated by (SIGINT)"); exit 0;};
    $SIG{'CHLD'} = sub { wait(); };
    
    logging("started");
    
    system ("rm -f `find /var/cache/machpause/*/ -type f -mtime +5 2>/dev/null`");
    
    while (1) {
	sleep 60;
	check_login();
    }
}

sub logging {
    my $log = shift;
    my $logdir = "/var/log";
    my $logfile = "$logdir/machpause.log";
    if (-d $logdir){
	my $file = IO::File->new(">>$logfile");
	if ($file) {
    	    flock($file, LOCK_EX);
    	    print {$file} "machpause: ". scalar localtime() .": ". $log ."\n";
    	    $file->close();
    	    chmod(0644, $logfile);
	}
    }
    return;
}

sub shutdown_maschine {
    logging("going shutdown maschine now");
    system("shutdown -h +1 &");
    return;
}

sub apps_stop {
    my $stop = shift;
    open STDOUT, '>>/dev/null' or die "Can't write to /dev/null: $!\n";
    open STDERR, '>>/dev/null' or die "Can't write to /dev/null: $!\n";
    my $pidfile = '/var/run/machpause.pid';
    if (-f $pidfile) {
        logging("Info: $pidfile found");
        system ("kill -9 `head -n 1 $pidfile` >/dev/null");
        if (!unlink("$pidfile")) {
            logging("Warning: Cannot remove $pidfile: $!");
            exit 1 if $stop;
        }else{
            logging("Info: remove $pidfile: $!");
            exit 0 if $stop;
        }
    }else{
        logging("Info: $pidfile not found");
        exit 0 if $stop;
    }
}

sub check_login {
    my %logins = ();
    my $pipe = IO::File->new("w -h |");
    if ($pipe) {
        while (<$pipe>){
            if (/^(\S+).*/){
		$logins{"$1"} = '1';
            }
        }
        $pipe->close();
    }
    foreach my $alias (keys %logins){
	check_config($alias);
    }
}

sub check_config {
    my $wuser = shift;
    my $config_dir = '/etc/machpause';
    my $today = `LANG=C date +%A`;
    chomp $today;
    if (-f "$config_dir/$today/$wuser") {
        my $ufile = IO::File->new("<$config_dir/$today/$wuser");
        if ($ufile) {
            NUMMER:
            while (<$ufile>) {
		if ( / \A \d+ \z /xms ) {
                    check_oldtime($wuser, $today, $_);
                    last NUMMER;
                }
            }
        $ufile->close();
        }
    }
}

sub check_oldtime {
    my $cuser = shift;
    my $daydir = shift;
    my $utime = shift;
    my $old_time = 0;
    my $cache_dir = "/var/cache/machpause";
    if (! -d "$cache_dir/$daydir") {
        system ("mkdir -p $cache_dir/$daydir");
        if (-d "$cache_dir") {
	    chmod(0755, "$cache_dir");
	}	
	if (-d "$cache_dir/$daydir") {
	    chmod(0755, "$cache_dir/$daydir");
	}
    }
    if (-d "$cache_dir/$daydir") {
        if (! -f "$cache_dir/$daydir/$cuser") {
            my $ifile = IO::File->new(">$cache_dir/$daydir/$cuser");
            if ($ifile) {
		chmod(0644, $ifile);
                print {$ifile} '0';
                $ifile->close();
            }
        }
        if (-f "$cache_dir/$daydir/$cuser") {
            my $cfile = IO::File->new("<$cache_dir/$daydir/$cuser");
            if ($cfile) {
                CACHE:
                while (<$cfile>) {
		    if ( / \A \d+ \z /xms ) {
                	$old_time = $_;
                	last CACHE;
            	    }
        	}
        	$cfile->close();
    	    }
        }
        my $newtime = $old_time + 1;
        my $afile = IO::File->new(">$cache_dir/$daydir/$cuser");
        if ($afile) {
	    chmod(0644, $afile);
            print {$afile} $newtime;
            $afile->close();
        }
	my $downtime = $utime - $newtime;
	my $bfile = IO::File->new(">$cache_dir/shutdown");
	if ($bfile) {
	    chmod(0644, $bfile);
	    print {$bfile} $downtime;
	    $bfile->close();
	}
	if ($newtime > $utime) {
	    shutdown_maschine();
	    apps_stop('1');
	}
    }
}

sub apps_status {
    exit 0;
}

### eof
