From 119a0b0d12dea51d1a5032552dbe8944308276ca Mon Sep 17 00:00:00 2001 From: Alex Harpin Date: Sat, 24 Jan 2015 15:01:33 +0000 Subject: vyatta-op: update the system poweroff cli command to be script based Update the system poweroff command to use the vyatta-poweroff.pl script rather than simply uisng the shutdown command. This allows other actions to be taken on shutdown, including correctly disconnecting SSH clients rather than having them resorting to timing out (Bug #298) Bug #460 http://bugzilla.vyos.net/show_bug.cgi?id=460 --- Makefile.am | 1 + scripts/vyatta-poweroff.pl | 189 ++++++++++++++++++++++++++++++++ templates/poweroff/at/node.tag/node.def | 7 +- templates/poweroff/cancel/node.def | 2 +- templates/poweroff/node.def | 9 +- templates/poweroff/now/node.def | 5 +- 6 files changed, 196 insertions(+), 17 deletions(-) create mode 100755 scripts/vyatta-poweroff.pl diff --git a/Makefile.am b/Makefile.am index d32cc56..410c419 100644 --- a/Makefile.am +++ b/Makefile.am @@ -60,6 +60,7 @@ sbin_SCRIPTS += scripts/vyatta-regen-unpriv-commands.sh bin_sudo_users_SCRIPTS = scripts/vyatta-identify-interface.pl bin_sudo_users_SCRIPTS += scripts/vyatta-delete-log-file.sh bin_sudo_users_SCRIPTS += scripts/vyatta-reboot.pl +bin_sudo_users_SCRIPTS += scripts/vyatta-poweroff.pl bin_sudo_users_SCRIPTS += scripts/vyatta-op-dns-forwarding.pl bin_sudo_users_SCRIPTS += scripts/vyatta-op-dynamic-dns.pl bin_sudo_users_SCRIPTS += scripts/vyatta-clear-conntrack diff --git a/scripts/vyatta-poweroff.pl b/scripts/vyatta-poweroff.pl new file mode 100755 index 0000000..9103900 --- /dev/null +++ b/scripts/vyatta-poweroff.pl @@ -0,0 +1,189 @@ +#!/usr/bin/perl +# +# Module: vyatta-poweroff.pl +# +# **** License **** +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# 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. +# +# This code was originally developed by Vyatta, Inc. +# Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc. +# All Rights Reserved. +# +# Based on the original vyatta-reboot script by Stig Thormodsrud +# +# Author: Alex Harpin +# Date: Jan 2015 +# Description: Script to shutdown or schedule a shutdown +# +# **** End License **** +# + +use lib "/opt/vyatta/share/perl5/"; +use Getopt::Long; +use POSIX; +use IO::Prompt; +use Sys::Syslog qw(:standard :macros); + +use strict; +use warnings; + +my $poweroff_job_file = '/var/run/poweroff.job'; + +sub parse_at_output { + my @lines = @_; + + foreach my $line (@lines) { + if ($line =~ /error/) { + return (1, '', ''); + } elsif ($line =~ /job (\d+) (.*)$/) { + return (0, $1, $2); + } + } + return (1, '', ''); +} + +sub is_poweroff_pending { + if ( ! -f $poweroff_job_file) { + return (0, ''); + } + my $job = `cat $poweroff_job_file`; + chomp $job; + my $line = `atq $job`; + if ($line =~ /\d+\s+(.*)\sa root$/) { + return (1, $1); + } else { + return (0, ''); + } +} + +sub do_poweroff { + my $login = shift; + + syslog("warning", "Poweroff now requested by $login"); + if (!system("sudo /sbin/shutdown -h now")) { + exec("sudo /usr/bin/killall sshd"); + } +} + +sub cancel_poweroff { + my ($login, $time) = @_; + + my $job = `cat $poweroff_job_file`; + chomp $job; + system("atrm $job"); + system("rm $poweroff_job_file"); + syslog("warning", "Poweroff scheduled for [$time] - CANCELED by $login"); +} + +my ($action, $at_time, $now); +GetOptions("action=s" => \$action, + "at_time=s" => \$at_time, + "now!" => \$now, +); + +if (! defined $action) { + die "no action specified"; +} + +openlog($0, "", LOG_USER); +my $login = getlogin() || getpwuid($<) || "unknown"; + +if ($action eq "poweroff") { + + my ($rc, $time) = is_poweroff_pending(); + if ($rc) { + if (defined $now) { + cancel_poweroff($login, $time); + do_poweroff($login); + } else { + print "Poweroff already scheduled for [$time]\n"; + exit 1; + } + } + + if (defined $now) { + do_poweroff($login); + } else { + if (prompt("Proceed with poweroff? (Yes/No) [No] ", -ynd=>"n")) { + do_poweroff($login); + } else { + print "Poweroff canceled\n"; + exit 1; + } + } +} + +if ($action eq "poweroff_at") { + if (! -f '/usr/bin/at') { + die "Package [at] not installed"; + } + + if (! defined $at_time) { + die "no at_time specified"; + } + + my ($rc, $rtime) = is_poweroff_pending(); + if ($rc) { + print "Poweroff already scheduled for [$rtime]\n"; + exit 1; + } + + my @lines = `echo true | at $at_time 2>&1`; + my ($err, $job, $time) = parse_at_output(@lines); + if ($err) { + print "Invalid time format [$at_time]\n"; + exit 1; + } + system("atrm $job"); + + print "\nPoweroff scheduled for $time\n\n"; + if (!prompt("Proceed with poweroff schedule? [confirm] ", -y1d=>"y")) { + print "Poweroff canceled\n"; + exit 1; + } + + @lines = `echo "sudo /sbin/shutdown -h now && sudo /usr/bin/killall sshd" | at $at_time 2>&1`; + ($err, $job, $time) = parse_at_output(@lines); + if ($err) { + print "Error: unable to schedule poweroff\n"; + exit 1; + } + system("echo $job > $poweroff_job_file"); + print "\nPoweroff scheduled for $time\n"; + syslog("warning", "Poweroff scheduled for [$time] by $login"); + + exit 0; +} + +if ($action eq "poweroff_cancel") { + + my ($rc, $time) = is_poweroff_pending(); + if (! $rc) { + print "No poweroff currently scheduled\n"; + exit 1; + } + cancel_poweroff($login, $time); + print "Poweroff canceled\n"; + exit 0; +} + +if ($action eq "show_poweroff") { + + my ($rc, $time) = is_poweroff_pending(); + if ($rc) { + print "Poweroff scheduled for [$time]\n"; + exit 0; + } else { + print "No poweroff currently scheduled\n"; + } + exit 1; +} + +exit 1; diff --git a/templates/poweroff/at/node.tag/node.def b/templates/poweroff/at/node.tag/node.def index ccc3b5b..932e04b 100644 --- a/templates/poweroff/at/node.tag/node.def +++ b/templates/poweroff/at/node.tag/node.def @@ -1,6 +1,3 @@ help: Poweroff the system at a future time -allowed: echo -n '' '' '+MM' -run: if /opt/vyatta/bin/vyatta-gettime.pl $3 >/tmp/shutdown.at - then (sudo /sbin/shutdown -h $3 & - disown %?sudo ) >/dev/null 2>&1 - fi +allowed: echo -n '' '' '' '' +run: sudo /opt/vyatta/bin/sudo-users/vyatta-poweroff.pl --action poweroff_at --at_time "$3" diff --git a/templates/poweroff/cancel/node.def b/templates/poweroff/cancel/node.def index c08a72d..c45f17a 100644 --- a/templates/poweroff/cancel/node.def +++ b/templates/poweroff/cancel/node.def @@ -1,2 +1,2 @@ help: Cancel a pending poweroff -run: sudo /sbin/shutdown -c +run: sudo /opt/vyatta/bin/sudo-users/vyatta-poweroff.pl --action poweroff_cancel diff --git a/templates/poweroff/node.def b/templates/poweroff/node.def index 44b8301..ccb7338 100644 --- a/templates/poweroff/node.def +++ b/templates/poweroff/node.def @@ -1,9 +1,2 @@ help: Poweroff the system -run: if [ "$VYATTA_PROCESS_CLIENT" == "gui2_rest" ] - then - sudo /sbin/shutdown -h now && sudo /usr/bin/killall sshd - else - ${vyatta_bindir}/yesno -n "Proceed with poweroff? (Yes/No) [No] " \ - && sudo /sbin/shutdown -h now && sudo /usr/bin/killall sshd - fi - +run: sudo /opt/vyatta/bin/sudo-users/vyatta-poweroff.pl --action poweroff diff --git a/templates/poweroff/now/node.def b/templates/poweroff/now/node.def index d9902cb..6b67572 100644 --- a/templates/poweroff/now/node.def +++ b/templates/poweroff/now/node.def @@ -1,3 +1,2 @@ -help: Poweroff the system now [disruptive] -run: sudo /sbin/shutdown -h now && sudo /usr/bin/killall sshd - +help: Poweroff the system without confirmation +run: sudo /opt/vyatta/bin/sudo-users/vyatta-poweroff.pl --action poweroff --now -- cgit v1.2.3