#!/usr/bin/perl

# Copyright (C) 2008-2015 Petter Reinholdtsen <pere@hungry.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

use strict;
use warnings;

use Sys::Syslog qw(openlog syslog closelog LOG_NOTICE);

my $delay = 5;
my $wakeupblock = "/etc/shutdown-at-night/shutdown-at-night-nowakeup-others";
my $wakeuplist = "/etc/shutdown-at-night/clients";
my $wakeupgenerator = "/etc/shutdown-at-night/clients-generator";

my %hwaddrs;

sub load_clients {
    my $fh = shift;
    while (<$fh>) {
        chomp;
        my ($ip, $hwaddr) = split(/\s+/);
        $hwaddrs{$ip} = $hwaddr;
    }
}

if ( -f $wakeupblock) {
    logmsg("not waking other clients, blocked by $wakeupblock");
    exit 0;
}

# Locate hosts to wake up, from file
if ( -f $wakeuplist ) {
    if (open(CLIENTS, "<", $wakeuplist)) {
        load_clients(*CLIENTS);
        close(CLIENTS);
    }
}
# Or using a dynamic script
if ( -x $wakeupgenerator ) {
    if (open(CLIENTS, "$wakeupgenerator |")) {
        load_clients(*CLIENTS);
        close(CLIENTS);
    }
}

my %alive;
map { $alive{$_} = 1; } get_alive_list(keys %hwaddrs);

# Calculate when to start, assuming 20-30 seconds between each host
#my $duration = $delay * scalar keys %hwaddrs;
#my $allup = time();

# Start sending wakeup calls
for my $ip (sort keys %hwaddrs) {
    if (! defined $alive{$ip}) {
        logmsg("sending wake-on-lan to $ip [$hwaddrs{$ip}]");
        wakeup($ip, $hwaddrs{$ip});
        sleep $delay;
    } else {
        logmsg("not sending wake-on-lan to already awake $ip [$hwaddrs{$ip}]");
    }
}

# exit
exit 0;

sub wakeup {
    my ($ip, $hwaddr) = @_;
    `wakeonlan $hwaddr`;
}

sub get_alive_list {
    my @addresses = @_;
    if ($#addresses > 0) {
        return split(/\s+/, `fping -a @addresses 2>/dev/null`);
    } else {
        return [];
    }
}

sub logmsg {
    my $msg = shift;
    openlog("wakeupclients", undef, 'user');
    syslog(LOG_NOTICE, "%s", $msg);
    closelog;
}
