powernap-2.18/0000775000175000017500000000000012064363035013543 5ustar roaksoaxroaksoaxpowernap-2.18/DESIGN0000664000175000017500000000610712064361217014443 0ustar roaksoaxroaksoaxpowernapd States * asleep * powernapd has successfully taken its action, and has not been awoken yet * system could be in: * custom (cpu is online, monitors can run) * powersaving (cpu is online, monitors can run) * suspended (cpu is offline) * hibernated (cpu is offline) * powered off (cpu is offline) * awake * cpu is online monitors can run Monitors * Network * WOLMonitor * event: bind to ports 7 and 9 and watch for magic packet * response: record timestamp on any WoL packet arrives wake immediately if asleep * default: watch udp:7 or udp:9 * UDPMonitor * event: bind to specified ports and watch for activity * response: record timestamp on any packet arrives on any of a list of specified udp ports wake immediately if asleep * default: no monitored ports * TCPMonitor * poll: run every INTERVAL seconds, looking for connections on specified ports * response: record timestamp on any established connection against a list of specified tcp ports wake immediately if asleep * default: no monitored ports (document that monitoring 22|80|443 might be useful) * User Input * USBMonitor * response: record timestamp on any activity on USB input wake immediately if asleep * default: keyboard and mouse * PS2Monitor * response: record timestamp on any activity on PS2 input wake immediately if asleep * default: keyboard and mouse * System * Process * poll: run every INTERVAL seconds, looking for matching processes * response: record timestamp on any process matching a list of regexes is running wake immediately if asleep * default: no monitored processes * ProcessIO * response: record timestamp on any process matching a list of regexes having active io wake immediately if asleep * default: no monitored processes * Load * poll: run every INTERVAL seconds, looking at /proc/loadavg * response: record timestamp if system load is too high wake immediately if asleep * default: system_load / num_cpus > .75 Approach 1: * Run all monitors all the time * Check all monitor timestamps every INTERVAL seconds * Take powernap action (powersave by default) if no timestamp in last ABSENT_SECONDS * Continue running monitors in powernap mode * Wake from powernap any time any timestamp from any running monitor shows up * This is potentially very expensive Approach 2: * Run awake-monitors while awake, asleep-monitors while asleep Approach 3: * Run all monitors at all times. * During ABSENT_SECONDS, check activity every INTERVAL seconds * During powersave, do NOT check every INTERVAL seconds, but use an EVENT based approach. * Example: - While in ABSENT_SECONDS TCPMonitor will be checked for activity every INTERVAL_SECONDS (10) - If activity was found within the last INTERVAL_SECONDS, then reset absent seconds of monitor. - While in POWERSAVE mode, the powernapd will stop polling, and TCPMonitor will send an EVENT - This EVENT will instruct machine to take RECOVER ACTION. powernap-2.18/config_migrate.py0000775000175000017500000000347012064361217017101 0ustar roaksoaxroaksoax#!/usr/bin/env python # # Script to migrate a v1.7 configuration file to a v1.xx configuration # file import os, sys # Parse command line if len(sys.argv) != 4: print 'Usage :- %s old_config old_action new_config' % sys.argv[0] old_cnf_path = sys.argv[1] old_act_path = sys.argv[2] new_cnf_path = sys.argv[3] # Load OLD config try: execfile(old_cnf_path) except Exception, e: print 'ERROR: failed to load old configuration [e=%s]' % e sys.exit(1) # Process new config file lines = [] try: fp = open(new_cnf_path, 'r') for l in fp.readlines(): l = l.strip() # Ignore blank, comment and section line if not l or l[0] in [ '#', '[' ]: lines.append(l) # Interval elif l.startswith('interval'): lines.append('interval = %0.2f' % INTERVAL_SECONDS) # Absent elif l.startswith('absent'): lines.append('absent = %0.2f' % ABSENT_SECONDS) # Grace elif l.startswith('grace'): lines.append('grace = %0.2f' % GRACE_SECONDS) # Debug elif l.startswith('debug'): lines.append('debug = %d' % DEBUG) # Action elif l.startswith('action_enter_sleep'): if os.access(old_act_path, os.X_OK): lines.append("action_enter_sleep = '%s'" % os.path.abspath(old_act_path)) else: lines.append(l) # Monitors elif l.startswith('monitors'): monitors = "monitors = [ \"InputMonitor()\"" for m in MONITORED_PROCESSES: monitors += ", \"ProcessMonitor({'regex':'%s'})\"" % m monitors += " ]" lines.append(monitors) # All else else: lines.append(l) fp.close() # Store data fp = open(new_cnf_path, 'w') for l in lines: fp.write(l + '\n') fp.close() except Exception, e: print 'ERROR: failed to update configuration [e=%s]' % e sys.exit(1) # Done print 'Configuration successfully updated' powernap-2.18/ChangeLog0000664000175000017500000004717512064363035015333 0ustar roaksoaxroaksoaxpowernap (2.18) released; urgency=low [ Frank Steinberg ] * LoadMonitor: handle float values correctly (LP: #1070696) * TCPMonitor: handle IPv6 connections correctly (LP: #1070695) [ Andres Rodriguez ] * debian/powernap.default: Add so that powernap does not start by default. -- Andres Rodriguez Mon, 04 Jun 2012 12:59:15 -0400 powernap (2.17-0ubuntu1) precise; urgency=low [ Bryce Harrington ] * actions/{service,kernel_module}: Add scripts to handle services and kernel modules on powersave mode. [ Andres Rodriguez ] * Re-organize source to differ between pm-utils actions and powernap actions. - debian/powernap-common.install: Update. - powernap.spec: Update. * Disable SERVICES and KERN_MODULES on PowerSave mode (LP: #887684): - powernap/powernap.py: Load from config. - debian/powernap-common.install: Install new scripts. - Add take powersave action and its recover equivalent. * actions/pm/01cpu_online: Disable by default. -- Andres Rodriguez Thu, 01 Dec 2011 12:43:51 -0500 powernap (2.16-0ubuntu1) precise; urgency=low [ Andres Rodriguez ] * debian/control: Move python-scapy Depends to Suggests. * Do not use awk to parse output. (LP: #879591) - bin/powerwake - powerwake/powerwake.py [ Eric Sandeen ] * powernap.spec: cleaned up a bit for better building/installation on RH systems [ Remi Druilhe ] * Dynamically reload configuration file (LP: #887680) -- Andres Rodriguez Tue, 29 Nov 2011 14:42:41 -0500 powernap (2.15-0ubuntu1) oneiric; urgency=low * actions/eth_speed: Disable by default to not experience connectivity loss on certain network configs. (LP: #730210) -- Andres Rodriguez Fri, 09 Sep 2011 15:32:30 -0400 powernap (2.14-0ubuntu1) oneiric; urgency=low * bin/powerwake: - fix the powerake mac caching methodology, which was somewhat broken -- Dustin Kirkland Mon, 22 Aug 2011 00:38:17 -0500 powernap (2.13-0ubuntu1) oneiric; urgency=low [ Dustin Kirkland ] * sbin/powernapd: - make sure that powerwake-now works, even if a system has gone into powersave mode by other means (erhm, gnome-power-settings, erhm) * actions/01cpu_online: - drop the nasty sleep 10 hack around gnome-settings-daemon bugginess; doesn't seem to be a problem at this point in Oneiric; If this bug shows back up, we need to solve it in a better way * actions/video: - drop incorrect inline docs * config: - now that the default is powersave mode, adjust the absent time and grace period; it takes fractions of a second to go in and out of powersave mode * actions/00flag, debian/powernap.upstart, sbin/powernapd: LP: #829618 - use a flag in shared memory that notes the powersave status of the system - set/remove that flag in the 00flag script in the pm-utils suite - set/remove/query that same flag in powernapd itself * debian/control: LP: #637635 - depend on anacron, to better handle server cronjobs on systems that might have been asleep * powernap/monitors/InputMonitor.py: LP: #826278 - test device path existence before opening, fixes nasty crash -- Dustin Kirkland Fri, 19 Aug 2011 09:57:07 -0700 powernap (2.12-0ubuntu1) oneiric; urgency=low [ Andres Rodriguez ] * Add Initial PowerNap (powerwaked) Server Capabilities: - powerwake/*: Add module and Initial ARPMonitor (LP: #737479). - powerwaked.conf: Add config file. - powerwaked: Add daemon. - powerwake-monitor: Add tool to add, delete, list, etc. * Package powernap-server: - debian/control: Add powerwaked, powerwake-common, powernap-server - debian/{powerwaked,powerwake-common}.install: Add - debian/powerwaked.upstart: Add upstart job. [ Dustin Kirkland ] * bin/powerwake: - only seed the arp cache if the argument is not already a mac address -- Andres Rodriguez Tue, 09 Aug 2011 15:28:35 -0400 powernap (2.11-0ubuntu1) oneiric; urgency=low * actions/01cpu_online: Delay disabling of CPU's when machine is Desktop to allow it to apply template and not crash. -- Andres Rodriguez Mon, 20 Jun 2011 18:08:09 -0400 powernap (2.10-0ubuntu1) oneiric; urgency=low * Add support for port ranges to TCPMonitor (LP: #760729) - powernap/monitors/TCPMonitor.py: Add support. - powernap/powernap.py: Ensure that ports are now passed as strings. - config: Update to reflect new feature. * debian/control: - Bump Build-Depends on debhelper. - Change python supported version. - Update Bzr-VCS to current. - Set Dustin as Original maintainer and set myself as maintainer. -- Andres Rodriguez Thu, 09 Jun 2011 16:42:59 -0400 powernap (2.9-0ubuntu1) oneiric; urgency=low * sbin/powernap, sbin/powernapd: - add an indicator to show when powernap is engaged, remove after waking * === added directory debian/source, debian/source/format: - add this back in (got a fix for release scripts) -- Dustin Kirkland Thu, 02 Jun 2011 17:43:23 -0400 powernap (2.8-0ubuntu1) oneiric; urgency=low [ Andres Rodriguez ] * Switch to dpkg-source 3.0 (quilt) format * Switch to dh_python2 instead of dh_pycentral * sbin/powernap: ACTION_METHOD is now passed as an argument. * Second Stage Action Method (LP: #711521) - config: Add config options. - powernap/powernap.py: Add loading of config values. - sbin/powernapd: Add logic to handle second stage action. [ Dustin Kirkland ] * config: remove trailing whitespace * debian/source/format, === removed directory debian/source: - drop these for now, as they're breaking the release scripts -- Dustin Kirkland Thu, 02 Jun 2011 16:51:20 -0400 powernap (2.7-0ubuntu1) oneiric; urgency=low [ Jim Heck ] * DiskMonitor: Tracks disks activity by monitoring its state. If "standby/sleeping" they are assumed to be inactive. (LP: #738764). [ Mathieu Bérard ] * actions/kms_powermode: Add action method to enable power management for radeon kms driver. Should be removed when applied upstream or pm-utils. [ Andres Rodriguez ] * sbin/powernapd: Take recover action when entered to powersave with powernap-now (LP: #768598) [ Dustin Kirkland ] * powernap/monitors/LoadMonitor.py: scale monitors correctly, LP: #777361 -- Dustin Kirkland Wed, 04 May 2011 14:44:50 -0500 powernap (2.6-0ubuntu1) natty; urgency=low [ Andres Rodriguez ] * debian/copyright: Update upstream authors and license years. * powernap/monitors/IOMonitor.py: If processes do not have a command line, search regex in the 'Name:' field of /proc//status (LP: #735452) * actions/cpu_frequency: Fix saving/restoring of wrong governor (LP: #743682) Thanks to Mathieu Berard for the patch. - Additionally, save 'ondemand' as default when acpi-support and ondemand are run on boot to handle special case when running on battery. * debian/powernap.{preinst,postinst}: Add logic to handle the upgrade of the config file as format has changed. (LP: #744588) - install copy of config file in /usr/share/powernap to help with this. -- Dustin Kirkland Fri, 01 Apr 2011 17:21:48 -0500 powernap (2.5-0ubuntu1) natty; urgency=low [ Andres Rodriguez ] * Add support to load confs from /etc/powernap/config.d. Added to leverage compatibility with other applications, such as Eucalytpus. (LP: #711587) -- Dustin Kirkland Mon, 14 Mar 2011 17:37:16 -0500 powernap (2.4-0ubuntu1) natty; urgency=low [ Andres Rodriguez ] * Fix wall message timestamp (LP: #718242) * Add powerwake-now support. Sends signal to powernapd to wakeup powersave mode if the daemon is in powersave. * debian/powernap.upstart: Add pre-stop. - Issues 'powerwake-now' to wake up system if stopping while in powersave. - Add 'sleep 3' to wait for recover action to take place before actually stopping powernapd. Otherwise, it won't recover. * bin/powernapd: Set flags back to initial values if GRACE PERIOD completed. Ensures that flags have correct values if powerwake-now signal was received. [ Dustin Kirkland ] * sbin/powernapd: only display wall message if action is other than powersave -- Dustin Kirkland Thu, 17 Feb 2011 07:36:20 -0600 powernap (2.3-0ubuntu1) natty; urgency=low [ Andres Rodriguez ] * config,sbin/powernapd,powernap/powernap.py: New option to decide if powernapd will WARN the user via a wall message. Default yes. * sbin/powernapd: Use a Timestamp when sending the wall message. * InputMonitor now only enables/disables keyboard and mouse monitoring. - powernap/monitors/InputMonitor.py: Match regex in /by-id for kbd. - powernap/powernap.py: Support only mouse/keyboard - config: Only add options for mouse/keyboard. * Enabled InputMonitors by default. - config: Enable. - powernap.py: Only try to initialize if "mouse" or "kbd" are connected by looking into /dev/input/by-id. * powernapd: Add SIGIO handler. Ignores failure caused when disconnecting a monitored USB InputDevice, that caused powernapd to stop running. [ Dustin Kirkland ] * man/powernap-action.8, man/powernap_calculator.1: fix lintian warnings, escpae hyphens * debian/control: update package descriptions -- Dustin Kirkland Tue, 08 Feb 2011 23:10:40 -0600 powernap (2.2-0ubuntu1) natty; urgency=low [ Andres Rodriguez ] * actions: - cpu_smp_sched,eth_wol: Dropped. pm-utils provides its own verion. - cpu_frequency: Store default governor to reset it to default value. * debian/rules: run dh_installdeb *after* dh_pycentral. * Add lintian-overrides (LP: #706974) * sbin/powernap: Fix pm-powersave command path. -- Dustin Kirkland Fri, 28 Jan 2011 10:46:38 -0600 powernap (2.1-0ubuntu1) natty; urgency=low [ Andres Rodriguez ] * config: - Default ACTION to pm-powersave instead of best-effort. - Enable WoLMonitor and ConsoleMonitor by default - Disable ProcessMonitor by default. - Change powersave defaults to 0 instead of 4. Update related files. * powernap/monitors: - Rename RemoteMonitor to UDPMonitor. - Add WoLMonitor and support to run it. - Add ConsoleMonitor and support to run it. * powernap/powernap.py: - Improve config loading method for Monitors. * sbin/powernapd: Change approach of powernapd_loop. - GRACE period is time between ABSENT_SECONDS and (ABSENT_SECONDS - GRACE_SECONDS) - Only send a Wall message when on GRACE Period. - Enable Monitors to run at all times. Specifically when in PowerSave. * man/powernapd.8: Update to list available Monitors with description. * Update Copyright years/email in some of the files. [ Dustin Kirkland ] * config, powernap/monitors/TCPMonitor.py, powernap/powernap.py: - add a TCP Monitor * config, powernap/monitors/LoadMonitor.py, powernap/powernap.py: - add a system Load Monitor * debian/control: bump standards version * debian/rules: make sure powernapd starts on install, LP: #705959 * config: update service restart method -- Dustin Kirkland Thu, 27 Jan 2011 16:38:22 -0600 powernap (2.0-0ubuntu1) natty; urgency=low [ Andres Rodriguez ] * powernap/monitors: Re-work Monitors to integrate them with PowerNap. * powernap/powernap.py: Minor fixes to not crash when loading monitors. * sbin/powernapd: Integrate Monitors approach to work with Daemon. * Update copyright headers for some files * Update manpages and add one for powernap-action. * Update packaging: - debian/control: Add python related fileds. - debian/rules: Add dh_pycentral related rules. * Add new package to contain new modules and monitors: - debian/control: Add package powernap-common. - debian/powernap-common.install: Install new files (PowerNap class and Monitors); Move action scripts installation to this package. * sbin/powernapd: Improve WoL monitor to listen in eth* interfaces. * config: Update and cleanup. * sbin/powernapd,bin/powerwake: Fix generation of WoL Magic Packet. Apparently, more data than required was addeed. (LP: #705943) -- Dustin Kirkland Sat, 22 Jan 2011 09:09:04 -0600 powernap (1.12-0ubuntu1) natty; urgency=low [ Andres Rodriguez ] * Revert Adam changes to some files (rev148 - Original PowerNap behavior) - powernapd, powernapd.8, action, config. * Re-organize the source and update the packaging: - sbin: Moved powernap, powernapd, powernapd-now. - bin: Moved powerwake, powernap_calculator. - man: Moved manpages here. - debian/{powernap,powerwake}.install: Update accordingly. - debian/{powernap,powerwake}.manpages: Update accordingly. - powernap/monitors: Moved Adam's Monitors. * Add new powersave method, using pm-powersave: - actions/: Add a set of scripts to reduce power consumption - powernap-action: Add tool to enable/disable and list powersave actions. - debian/powernap.install: Install new files. * Provide ability to select a PowerNap method to perform. - config: Add config variable to select method. - powernap/{powernap,powernapd}: Make necessary changes. * Add WoL monitor to 'wake up' for when 'pm-powersave' action is taken. - sbin/powernapd: Add WoL Monitor. - sbin/powerna: Take pm-powersave action correctly. * Add class to handle config: - powernap/powernap.py: Add class that handles config and initialization of different monitors -- Dustin Kirkland Tue, 11 Jan 2011 12:59:13 -0600 powernap (1.11-0ubuntu1) natty; urgency=low [ Adam Sutton ] * reworked config file and config file parsing * modularized the monitoring to a set of logical plugins * added a monitor on a UDP port for staying awake [ Nobuto MURATA ] * powerwake_completion: add bash completion from $HOME/.cache/ethers, LP: #675445 * debian/powernap.upstart: fix LP: #598241 cannot enable Wake-on-LAN when ifconfig output is translated [ Dustin Kirkland ] * powerwake: test if home dir is writable (might not be, eg: www-data) -- Dustin Kirkland Wed, 17 Nov 2010 17:15:25 -0600 powernap (1.10-0ubuntu1) maverick; urgency=low [ Nobuto MURATA ] * debian/powerwake.install, powerwake_completion: add bash completion for powerwake, LP: #551073 [ Dustin Kirkland ] * powerwake: create the ~/.cache/ethers file, if it does not already exist, LP: #582381 -- Dustin Kirkland Tue, 18 May 2010 12:33:32 -0500 powernap (1.9-0ubuntu1) lucid; urgency=low * debian/powernap.upstart: fix LP: #531950 - fix ethtool regex - allow for admin customized ethtool script, when powernap's is incorrect or undesired -- Dustin Kirkland Thu, 04 Mar 2010 11:04:49 -0600 powernap (1.8-0ubuntu1) lucid; urgency=low * powerwake: - test ethers file for writability, LP: #458163 - since non-priv users cannot write to globally cached ethers, support local user eth caches * powernap-now, debian/install: - add a powernap-now utility, for sending the 'now' signal to the daemon * debian/powernap.manpages, powernap-now.8: - add powernap-now manpages * debian/powernap.init, debian/powernap.upstart, debian/rules: - upstart-ify powernap -- Dustin Kirkland Sat, 06 Feb 2010 22:34:34 -0600 powernap (1.7-0ubuntu1) karmic; urgency=low * debian/powernap.init: enable WoL at boot on interface(s) that support wake-on-lan, to ensure that a powernapping system can be awoken later, LP: #445950 -- Dustin Kirkland Wed, 19 Aug 2009 00:19:13 -0500 powernap (1.6-0ubuntu1) karmic; urgency=low [ Dan Nurmi ] * powerwake: add support for a broadcast argument, add getopt support [ Dustin Kirkland ] * powerwake.1: updated to handle Dan's extensions and new arguments * powernap_calculator, powernap_calculator.1: new script to help determine the expected power savings usings powernap in a cloud environment; manpage documentation added * debian/powernap.logrotate: rotate the powernap log * powernapd: overhaul powernap's logging using python's built-in logging functionality * debian/control: bump standards version -- Dustin Kirkland Tue, 18 Aug 2009 19:12:43 -0500 powernap (1.5-0ubuntu1) karmic; urgency=low * powerwake: handle more gracefully the lack of an /etc/ethers file * powernapd: fix timestamp -- Dustin Kirkland Fri, 10 Jul 2009 17:37:54 -0500 powernap (1.4-0ubuntu1) karmic; urgency=low * powerwake: maintain and use a cache of mac addresses, in /var/cache/powerwake/ethers; test is_mac() before adding to arp hash * debian/powerwake.dirs, debian/powerwake.install, debian/powerwake.postinst, debian/control: add a separate powerwake package * debian/manpages, debian/powerwake.manpages: added manpage debhelper files * debian/control: recommend ethtool, which might be necessary to enable wake-on-lan on your ethernet card, powernap depends on pm-utils * powernap -> powernapd, debian/init, debian/install: rename the python powernap daemon 'powernapd' * powernap.1 -> powernapd.8: renamed, note ethtool * powernap: new script that will either take a specified action, or run one of (pm-suspend, pm-hibernate, poweroff) * powernap.8: document new script * action: conffile describing what should go there * debian/init: drop stdout on 'now' status check * debian/*: use powernap.* and powerwake.* to remove any ambiguity * powernapd: look for activity on /dev/* consoles and in /proc/interrupts during the grace period, such that any activity will cancel the powernap operation * powerwake, powerwake.1: update to allow for static configuration override in /etc/ethers -- Dustin Kirkland Thu, 09 Jul 2009 17:28:44 -0500 powernap (1.3-0ubuntu1) karmic; urgency=low * config: add default value statement to each item; add sane defaults; add grace period section * powernap: add a system-wide warning message using 'wall', and a grace seconds interval to cancel the operation of 60 seconds (by default); move to using global variables for options defined in the config file * debian/control: depend on bsdutils for 'wall' utility -- Dustin Kirkland Mon, 29 Jun 2009 14:49:55 -0700 powernap (1.2-0ubuntu1) karmic; urgency=low * config, debian/control, powernap.1, powernap.py: lower the default polling period from 10 seconds to 1 second; polling /proc is cheap, and empirical testing has shown a negligible performance impact; add a note about DEBUG * powernap.py -> powernap: - abstract take_action() to a function, add a handler for --now - daemonize within the python script - eliminate the shell wrapper - log to /var/log/powernap.* - add signal handling for "now", USR1 * powernap.1: add log files * debian/init: add 'now' action and signal passing * powerwake: initial cut at powerwake utility * powerwake.1: initial cut at powerwake documentation -- Dustin Kirkland Fri, 26 Jun 2009 17:23:22 -0500 powernap (1.1-0ubuntu1) karmic; urgency=low * debian/copyright: updated for Ubuntu inclusion -- Dustin Kirkland Fri, 12 Jun 2009 12:53:54 -0500 powernap (1.0-0ubuntu1) karmic; urgency=low [ Initial release ] * powernap: shell wrapper script * powernap.py: python daemon * config: global configuration file * powernap.1: manpage documentation -- Dustin Kirkland Thu, 11 Jun 2009 17:30:16 -0500 powernap-2.18/actions/0000775000175000017500000000000012064361217015203 5ustar roaksoaxroaksoaxpowernap-2.18/actions/pm/0000775000175000017500000000000012064361217015617 5ustar roaksoaxroaksoaxpowernap-2.18/actions/pm/kms_powermode0000664000175000017500000000372212064361217020421 0ustar roaksoaxroaksoax#!/bin/sh # # kms_powersave: this script switchs between GPU power mode # # Copyright (C) 2011 Mathieu Bérard # # Authors: Mathieu Bérard # # 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, version 3 of the License. # # 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, see . # Only support radeon kms driver pm modes for now. # The sysfs interface is explained here, I highly recommend reading it # before tweaking this script: # http://lists.freedesktop.org/archives/dri-devel/2010-May/000492.html #Full power, default profile mode #Laptops may benefit from using FULL_PROFILE="auto" FULL_METHOD="profile" FULL_PROFILE="default" #Alternativly dynpm mode #FULL_METHOD="dynpm" #FULL_PROFILE="default" #Powersave mode LOW_METHOD="profile" LOW_PROFILE="low" DRM_PATH="/sys/class/drm/card0/device" DRM_DRIVER="${DRM_PATH}/driver" METHOD_SYSFILE="${DRM_PATH}/power_method" PROFILE_SYSFILE="${DRM_PATH}/power_profile" [ -e $DRM_DRIVER ] && [ -w $METHOD_SYSFILE ] && [ -w $METHOD_SYSFILE ] || exit 0 #At this point we should be using the radeon driver, but let's be extra carefull. DRM_DRIVER=`readlink -f ${DRM_DRIVER}` DRM_DRV_NAME=`basename ${DRM_DRIVER}` [ "$DRM_DRV_NAME" = "radeon" ] || exit 0 set_kms_power() { echo $1 > $PROFILE_SYSFILE echo $2 > $METHOD_SYSFILE } help() { echo "Radeon KMS power mode to save power." } case $1 in true) set_kms_power $LOW_PROFILE $LOW_METHOD ;; false) set_kms_power $FULL_PROFILE $FULL_METHOD ;; help) help;; *) exit $NA ;; esac powernap-2.18/actions/pm/01cpu_online0000664000175000017500000000220012064361217020030 0ustar roaksoaxroaksoax#!/bin/sh # # turn_off_cpus: This script turns off all the CPU's available, except # for CPU 0. # # Copyright (C) 2010 Canonical Ltd. # # Authors: Andres Rodriguez # # 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, version 3 of the License. # # 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, see . set_cpu_online() { for cpu in /sys/devices/system/cpu/cpu*/online; do [ -w "$cpu" ] || continue echo $1 > $cpu done } help() { echo "Turns off all the CPU's (cores) available but CPU0." } case $1 in true) # Disable CPU set_cpu_online 0 ;; false) # Enable CPU set_cpu_online 1 ;; help) help;; *) exit $NA ;; esac powernap-2.18/actions/pm/eth_speed0000664000175000017500000000221712064361217017504 0ustar roaksoaxroaksoax#!/bin/sh # # nic_giga_to_meg: Change gigabit ethernet card to 100Mpbs to save power # # Copyright (C) 2010 Canonical Ltd. # # Authors: Andres Rodriguez # # 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, version 3 of the License. # # 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, see . set_eth_speed() { if [ $1 -eq 100 ]; then # Save power ethtool -s eth0 autoneg off speed $1 else # Roll back to Gigabit ethtool -s eth0 autoneg on speed $1 fi } help() { echo "Change Gigabit Ethernet card speed to 100Mbps to save power." } case $1 in true) set_eth_speed 100 ;; false) set_eth_speed 1000 ;; help) help;; *) exit $NA ;; esac powernap-2.18/actions/pm/cpu_frequency0000775000175000017500000000424312064361217020420 0ustar roaksoaxroaksoax#!/bin/sh # # lowest_cpu_freq: This script lowers the frequency of the cpus by changing # the scaling_governor from "ondemand" to "powersave" # # Copyright (C) 2010 Canonical Ltd. # # Authors: Andres Rodriguez # # 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, version 3 of the License. # # 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, see . RUNDIR="/var/run/powernap" GOVERNOR="/var/run/powernap/cpu_governor.default" CPUFILE="/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor" full_power=`head -1 $CPUFILE` save_power="powersave" # Creates the $RUNDIR if it does not exists if [ ! -f $RUNDIR ]; then mkdir -p $RUNDIR fi # If governor is set to ondemand on boot, save as the default governor. # NOTE: Only for cases when Ubuntu machine is running on *battery* and # 'pm-powersave true' is executed on boot by S99acpi-support (power.sh), # and before the governor is set to ondemand. Otherwise, it will save # 'performance' as the default governor. if [ -h /etc/rc3.d/S99acpi-support ] && [ -h /etc/rc3.d/S99ondemand ]; then full_power="ondemand" fi set_cpu_governor() { for cpu in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do [ -w "$cpu" ] || continue echo $1 > $cpu done } help() { echo "Lowers the CPU frequency, changing the scaling governor from $full_power to $save_power." } case $1 in true) # Save current governor and change governor to powersave if [ ! -f $GOVERNOR ]; then echo $full_power > $GOVERNOR fi set_cpu_governor $save_power ;; false) # Restore governor to default if [ -f $GOVERNOR ]; then full_power=`head -1 $GOVERNOR` set_cpu_governor $full_power fi ;; help) help;; *) exit $NA ;; esac powernap-2.18/actions/pm/00flag0000775000175000017500000000221012064361217016611 0ustar roaksoaxroaksoax#!/bin/sh # # flag: touch or remove a flag file, indicating powersave mode; # # Copyright (C) 2011 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . RUNDIR="/var/run/powernap" FLAG="$RUNDIR/powersave" # Create the $RUNDIR if it does not exists mkdir -p "$RUNDIR" # This flag is necessary if there are multiple power managers on the system # using pm-powersave (eg, powernap, gnome-power-manager) case $1 in true) touch "$FLAG" ;; false) rm -f "$FLAG" ;; query) [ -e "$FLAG" ] && exit 0 || exit 1 ;; esac powernap-2.18/actions/pm/usb_autosuspend0000775000175000017500000000237212064361217020774 0ustar roaksoaxroaksoax#!/bin/sh # # usb_autosuspend: Auto suspend usb core. # # Copyright (C) 2010 Canonical Ltd. # # Authors: Andres Rodriguez # # 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, version 3 of the License. # # 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, see . #for i in /sys/bus/usb/devices/*/power/autosuspend; do echo 1 > $i; done #for i in /sys/bus/usb/devices/*/power/level; do echo auto > $i; done set_usb_autosuspend() { for i in /sys/bus/usb/devices/*/power/autosuspend; do echo $1 > $i done for i in /sys/bus/usb/devices/*/power/level; do echo $2 > $i done } help() { echo "Auto suspend USB bus to save power." } case $1 in true) set_usb_autosuspend 1 auto ;; false) set_usb_autosuspend 2 on ;; help) help;; *) exit $NA ;; esac powernap-2.18/actions/pm/video0000664000175000017500000000211312064361217016645 0ustar roaksoaxroaksoax#!/bin/sh # # disable_crt_dvi: Disable CRT and DVI outputs. # # Copyright (C) 2010 Canonical Ltd. # # Authors: Andres Rodriguez # # 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, version 3 of the License. # # 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, see . video="/proc/acpi/ibm/video" disable_crt_dvi() { if [ -w "$video" ]; then echo crt_$1 > $video echo dvi_$1 > $video echo lcf_$1 > $video fi } help() { echo "Disable CRT and DVI outputs." } case $1 in true) disable_crt_dvi disable ;; false) disable_crt_dvi enable ;; help) help;; *) exit $NA ;; esac powernap-2.18/actions/pm/usb0000664000175000017500000000203412064361217016332 0ustar roaksoaxroaksoax#!/bin/sh # # usb_remove_one: Removes support for USB 1.1 to save power. # # Copyright (C) 2010 Canonical Ltd. # # Authors: Andres Rodriguez # # 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, version 3 of the License. # # 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, see . usb_remove_one() { if [ $1 -eq 1 ]; then rmmod uhci_hcd else modprobe uhci_hcd fi } help() { echo "Removes support of USB 1.1 to save power." } case $1 in true) usb_remove_one 1 ;; false) usb_remove_one 0 ;; help) help;; *) exit $NA ;; esac powernap-2.18/actions/powernap/0000775000175000017500000000000012064361217017036 5ustar roaksoaxroaksoaxpowernap-2.18/actions/powernap/service0000775000175000017500000000345112064361217020427 0ustar roaksoaxroaksoax#!/bin/sh # # service: Disable/enable services (e.g. upstart wrapper) # # Copyright (C) 2011 Canonical Ltd. # # Authors: Bryce Harrington # # 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, version 3 of the License. # # 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, see . RUNDIR="/var/run/powernap" SERVICES="${RUNDIR}/services" disable_service() { service_name=$1 echo "$service_name" if [ -e /etc/init.d/${service_name} ]; then mkdir -p ${SERVICES} OUTPUT=$(service ${service_name} stop) echo "$OUTPUT" echo "OFF" > ${SERVICES}/${service_name} fi } enable_service() { service_name=$1 echo "$service_name" if [ -e /etc/init.d/${service_name} ] && \ [ -e ${SERVICES}/${service_name} ]; then state=$(cat ${SERVICES}/${service_name}) if [ ${state} != 'OFF' ]; then echo "WARNING: powernap shows ${service_name} in state {$state}. Trying to re-enable anyway." fi OUTPUT=$(service ${service_name} start) echo "$OUTPUT" echo "ON" > ${SERVICES}/${service_name} fi } help() { echo "Usage: $0 " echo "Ensure given service running" } case $1 in true) disable_service $2 ;; false) enable_service $2 ;; help) help ;; *) exit $NA ;; esac powernap-2.18/actions/powernap/kernel_module0000775000175000017500000000276312064361217021621 0ustar roaksoaxroaksoax#!/bin/sh # # kernel_module: Loads/unloads kernel modules # # Copyright (C) 2011 Canonical Ltd. # # Authors: Bryce Harrington # # 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, version 3 of the License. # # 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, see . RUNDIR="/var/run/powernap" MODULES="${RUNDIR}/modules" unload_module() { module_name=$1 lsmod | grep "^$module_name " >/dev/null if [ $? != 1 ]; then rmmod ${module_name} mkdir -p ${MODULES} echo 'UNLOADED' > ${MODULES}/${module_name} fi } reload_module() { module_name=$1 lsmod | grep "^${module_name} " >/dev/null if [ $? = 1 ] && \ [ -e ${MODULES}/${module_name} ]; then modprobe ${module_name} echo 'LOADED' > ${MODULES}/${module_name} fi } help() { echo "Usage: $0 " echo "Ensure given kernel module is [not] loaded" } case $1 in true) unload_module $2 ;; false) reload_module $2 ;; help) help ;; *) exit $NA ;; esac powernap-2.18/powernap.spec0000664000175000017500000001746712064361217016271 0ustar roaksoaxroaksoax# powernap.spec %define version 2.15 %define release 1 %define _unpackaged_files_terminate_build 0 Summary: Powernap Name: powernap Version: %{version} Release: %{release} License: GPL Group: Applications/System Source0: %{name}_%{version}.orig.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version} Requires: %{name}_%{version}=upstart >= 0.6.5 %description PowerNap is a configurable daemon that will bring a running system to a lower power state according to a set of configuration preferences. It acts as a sort of "screensaver" for servers, watching the process table for activity rather than the keyboard or mouse. PowerNap will run $ACTION when none of $PROCESSES have executed for some number of $ABSENCE seconds. For instance, PowerNap can automatically "pm-suspend" a system if no instance of "kvm" runs for some contiguous block of "300" seconds. # Sub package section used to generate powernap-common rpms %package -n powernap-common Summary: powernap-common Version: %{version} Release: %{release} Group: Applications/System Requires: powernap-common_%{version}=upstart >= 0.6.5 %description -n powernap-common This package contains the common library files required as a runtime dependency of powernap. # Sub package section used to generate powerwake rpms %package -n powerwake Summary: powerwake Version: %{version} Release: %{release} Group: Applications/System Requires: powerwake_%{version}=upstart >= 0.6.5 %description -n powerwake PowerWake is a generic mechanism for remotely waking systems. It is intended to support wake-on-lan, ipmi, and other remote waking mechanisms. Currently, wake-on-lan is the only supported mechanism. It also includes some handy caching of MAC addresses, such that systems can be awakened by hostname or ip address, in addition to MAC address. # prep section is used to setup the build environment for the software is created and directing # RPM through the process of preparing the software for building %prep %setup # Create the temporary build directory to build the rpms %install for x in $RPM_BUILD_ROOT $RPM_BUILD_ROOT/usr $RPM_BUILD_ROOT/usr/sbin $RPM_BUILD_ROOT/usr/bin $RPM_BUILD_ROOT/usr/share $RPM_BUILD_ROOT/usr/share/man $RPM_BUILD_ROOT/usr/lib/python2.7 $RPM_BUILD_ROOT/usr/lib/python2.7/dist-packages $RPM_BUILD_ROOT/usr/lib/python2.7/dist-packages/powernap $RPM_BUILD_ROOT/usr/lib/python2.7/dist-packages/powernap/monitors $RPM_BUILD_ROOT/usr/share/man/man1 $RPM_BUILD_ROOT/usr/share/man/man8 $RPM_BUILD_ROOT%python_sitelib $RPM_BUILD_ROOT%python_sitelib/powernap $RPM_BUILD_ROOT%python_sitelib/powernap/monitors $RPM_BUILD_ROO/usr/share/doc/powernap/ $RPM_BUILD_ROOT/etc $RPM_BUILD_ROOT/etc/init $RPM_BUILD_ROOT/etc/init.d $RPM_BUILD_ROOT/etc/logrotate.d $RPM_BUILD_ROOT/etc/bash_completion.d/ $RPM_BUILD_ROOT/etc/powernap $RPM_BUILD_ROOT/etc/pm $RPM_BUILD_ROOT/etc/pm/power.d ; do install -d $x done # Install the necessary files to the build directory to generate rpms # Installing all super user binaries in /usr/sbin pushd $RPM_BUILD_ROOT/usr/sbin for x in powernap powernapd powernap-now powernap-action powerwake-now ; do install -D %_topdir/BUILD/powernap-%{version}/sbin/$x $RPM_BUILD_ROOT/usr/sbin done popd # Installing all binaries in /usr/bin pushd $RPM_BUILD_ROOT/usr/bin for x in powernap_calculator powerwake ; do install -D %_topdir/BUILD/powernap-%{version}/bin/$x $RPM_BUILD_ROOT/usr/sbin done popd install -D %_topdir/BUILD/powernap-%{version}/powerwake_completion $RPM_BUILD_ROOT/etc/bash_completion.d # Installing configuration files in /etc/powernap pushd $RPM_BUILD_ROOT/etc/powernap for x in action config ; do install -D %_topdir/BUILD/powernap-%{version}/$x $RPM_BUILD_ROOT/etc/powernap done popd pushd $RPM_BUILD_ROOT/etc/pm/power.d for x in 01cpu_online cpu_frequency eth_speed usb usb_autosuspend video ; do install -D %_topdir/BUILD/powernap-%{version}/actions/pm/$x $RPM_BUILD_ROOT/etc/pm/power.d done popd # Installing all powernap specific python scripts pushd $RPM_BUILD_ROOT%python_sitelib for x in __init__.py powernap.py ; do install -D %_topdir/BUILD/powernap-%{version}/powernap/$x $RPM_BUILD_ROOT%python_sitelib/powernap done popd # Installing all powernap specific python scripts pushd $RPM_BUILD_ROOT%python_sitelib/powernap/monitors for x in ProcessMonitor.py ConsoleMonitor.py IOMonitor.py InputMonitor.py LoadMonitor.py Monitor.py TCPMonitor.py UDPMonitor.py WoLMonitor.py __init__.py ; do install -D %_topdir/BUILD/powernap-%{version}/powernap/monitors/$x $RPM_BUILD_ROOT%python_sitelib/powernap/monitors done popd # Installing man pages in man1 directory assuming that the source is present in # %_topdir/BUILD/powernap-%{version} directory pushd $RPM_BUILD_ROOT/usr/share/man/man1 for x in powernap_calculator.1 powerwake.1 ; do gzip %_topdir/BUILD/powernap-%{version}/man/$x install -D %_topdir/BUILD/powernap-%{version}/man/$x.gz $x.gz done popd # Installing man pages in man8 directory assuming that the source is present in # %_topdir/BUILD/powernap-%{version} directory pushd $RPM_BUILD_ROOT/usr/share/man/man8 for x in powernap.8 powernapd.8 powernap-now.8 powerwake-now.8 powernap-action.8 ; do gzip %_topdir/BUILD/powernap-%{version}/man/$x install -D %_topdir/BUILD/powernap-%{version}/man/$x.gz $x.gz done popd # Creating soft links for powernap python scripts pushd $RPM_BUILD_ROOT/usr/lib/python2.7/dist-packages/powernap/ for x in __init__.py powernap.py ; do rm -f $x; /bin/ln -sf ../../../../share/pyshared/powernap/$x $x done popd # Creating soft links for powernap python scripts pushd $RPM_BUILD_ROOT/usr/lib/python2.7/dist-packages/powernap/monitors for x in ProcessMonitor.py ConsoleMonitor.py IOMonitor.py InputMonitor.py LoadMonitor.py Monitor.py TCPMonitor.py UDPMonitor.py WoLMonitor.py __init__.py ; do rm -f $x; /bin/ln -sf ../../../../../share/pyshared/powernap/monitors/$x $x done popd # To clean up any files that are not part of the application's normal build area %clean #rm -rf $RPM_BUILD_ROOT #rm -rf %_topdir/BUILD/powernap-%{version} # Files section contains list of the files that are part of the rpm %files -n powernap %defattr(-, root, root, 0555) /usr/sbin/powernap /usr/sbin/powernapd /usr/sbin/powernap-now /usr/sbin/powernap-action /usr/sbin/powerwake-now /usr/sbin/powernap_calculator /etc/powernap/action /etc/powernap/config /usr/share/man/man8/powernapd.8.gz /usr/share/man/man8/powernap-now.8.gz /usr/share/man/man8/powernap.8.gz /usr/share/man/man8/powerwake-now.8.gz /usr/share/man/man8/powernap-action.8.gz /usr/share/man/man1/powernap_calculator.1.gz # Files to be added in powernap-common rpm %files -n powernap-common /etc/pm/power.d/01cpu_online /etc/pm/power.d/cpu_frequency /etc/pm/power.d/eth_speed /etc/pm/power.d/usb /etc/pm/power.d/usb_autosuspend /etc/pm/power.d/video %python_sitelib/powernap/__init__.py %python_sitelib/powernap/monitors/ProcessMonitor.py %python_sitelib/powernap/monitors/ConsoleMonitor.py %python_sitelib/powernap/monitors/IOMonitor.py %python_sitelib/powernap/monitors/InputMonitor.py %python_sitelib/powernap/monitors/LoadMonitor.py %python_sitelib/powernap/monitors/Monitor.py %python_sitelib/powernap/monitors/TCPMonitor.py %python_sitelib/powernap/monitors/UDPMonitor.py %python_sitelib/powernap/monitors/WoLMonitor.py %python_sitelib/powernap/monitors/__init__.py %python_sitelib/powernap/powernap.py # Files to be added in powerwake rpm %files -n powerwake /usr/sbin/powerwake /usr/share/man/man1/powerwake.1.gz /etc/bash_completion.d/powerwake_completion %changelog * Mon Mar 21 2011 Nandakumar Raghavan - Spec file to build and generate powernap rpms for RedHat based distros (Revision 3) * Fri Mar 4 2011 Nandakumar Raghavan - Spec file to build and generate powernap rpms for RedHat based distros (Revision 2) * Tue Mar 3 2011 Nandakumar Raghavan - Spec file to build and generate powernap rpms for RedHat based distros powernap-2.18/config0000664000175000017500000002032412064361217014734 0ustar roaksoaxroaksoax[powernap] # This is the configuration file for PowerNap. # See powernap(1) for more information. # This file is Python syntax, and will be sourced by the powernap daemon # on start. To enact changes to this configuration, restart the daemon. # Example: # sudo service powernap restart # The ACTION_METHOD variable determines what action to take. # The possible actions are: # 0 - powersave # 1 - suspend # 2 - hibernate # 3 - poweroff # 4 - best-effort # The default mode of operation is powersave. This method will use the # "pm-powersave" command and will execute hooks locate in "/etc/pm/power.d" and # "/usr/lib/pm-utils/power.d". # The best-effort method, witll first, it will try a user-defined script # at "/etc/powernap/action", or suspend, hibernate, poweroff. ACTION_METHOD = 0 # Number of seconds that all monitors must have no activity or must be absent. # The default is an absence period of 30 seconds. # Example: # ABSENT_SECONDS = 30 ABSENT_SECONDS = 30 # Grace period, after (ABSENT_SECONDS - GRACE_SECONDS) have elapsed with all of # the Monitors with absent activity, the system will send a Wall message for an # administrator to warn that the system will perform the "/usr/sbin/powernap" # action in GRACE_SECONDS. # The default grace period is 6 seconds. # Example: # GRACE_SECONDS = 6 GRACE_SECONDS = 6 # The powernap daemon will wake every INTERVAL_SECONDS and check for activity # to all of the monitors. Lower values of INTERVAL_SECONDS will provide # more detailed process monitoring but will consume more system resources. # Higher values of INTERVAL_SECONDS will consume less system resources, but # might miss activity that execute for less than INTERVAL_SECONDS. # The minimum runtime of any monitor should not be less than INTERVAL_SECONDS. # The default interval is 1 second. # Example: # INTERVAL_SECONDS = 1 INTERVAL_SECONDS = 1 # The powernap daemon will issue a warning message to the console whenever it # has entered into GRACE period. This warning message will warn the user that # it is about to perform an ACTION. # This warning message is done using the "wall" command, notifying all the # users connected to a console. # The default is set to 'yes' to WARN the user. It can be disabled by setting # the option to 'n' or 'no', or can simply be commented. # Example # WARN = y # WARN = n WARN = y # The powernap daemon logs errors to /var/log/powernap.err, and some basic # information to /var/log/powernap.log. To change the verbosity of this # logging, set DEBUG to 0, 1, 2, or 3: # The default debug level is 0. # DEBUG = 1 # DEBUG = 2 DEBUG = 0 # The powernap daemon can watch for changes in the configuration file in # /etc/powernap directory without having to restart it. # The default value is n. # WATCH_CONFIG = y # WATCH_CONFIG = n WATCH_CONFIG = n # Kernel Modules that are to be disabled when running PowerNap on Powersave # mode #KERN_MODULES = btusb sco tfcomm bnep # Network Services that are to be disabled when running PowerNap on # PowerSave mode #SERVICES = postgresql-8.4 apache2 ntp network-manager ############################################################################ #### STAGE2 ACTION #### ############################################################################ [powernap-stage2] # Number of seconds that all monitors must have no activity or must be absent # while running in PowerSave mode to perform the STAGE2_ACTION_METHOD. # The default value is to be disabled by default. If you wish to enable the # Second Stage Action method, set the STAGE2_ABSENT_SECONDS and ensure that # STAGE2_ACTION_METHOD is set correctly. # Example: # STAGE2_ABSENT_SECONDS = 500 STAGE2_ABSENT_SECONDS = 0 # The STAGE2_ACTION_METHOD variable determines what action should be taken # after a period on inactivity while under PowerSave Mode (See ACTION_METHOD # above). # The possible actions are: # 1 - suspend # 2 - hibernate # 3 - poweroff # 4 - best-effort # The default mode of operation is best-effort. This method will try to # user-defined script at "/etc/powernap/action", or suspend, hibernate, # or poweroff the machine. STAGE2_ACTION_METHOD = 4 ############################################################################ #### MONITORS #### ############################################################################ # The [WoLMonitor] section lists all ports on which the WoL Monitor will be # listening for WoL Packets for any of the network interfaces. # Once a WoL Packet is received, the WoLMonitor will compare the data received # with all the network interfaces (eth's) to determine wether it is destined # for any of the network interfaces. # The default is to monitor ports 7 and 9 for WoL data packets. It can also be # set to any other port on which the machine is receiving WoL packets # Example: # wol1052 = 1052 [WoLMonitor] wol7 = 7 wol9 = 9 # The [ConsoleMonitor] section enables or disables monitoring of activity # in the Console (tty), also tracking activity from any locally connected # mouse and keyboard (PS2 Only). # The default is enabled, set to 'y'. It can be disabled by setting it to 'n'. # Examples: # console = y # console = n [ConsoleMonitor] ptmx = y # The [ProcessMonitor] section lists all the processes to Monitor by using # regular expressions. # Each item listed will be compared against the output of "ps -eo args". # The default is to monitor /sbin/init, which should always be running. # Examples: # mplayer = "mplayer " # sshd = "sshd: .*\[priv\]$" # kvm = "kvm " [ProcessMonitor] #init = "^/sbin/init" # The [LoadMonitor] section defines the load threshold. When the system load # according to /proc/loadavg is above this value, then system will be deemed # 'active' and will not powernap. If the system is already powernapping, then # the system will awake out of the powernap mode if the load raises above the # threshold. # If the threshold is set to "n" (which is default), threshold is automatically # calculated to be the number of online processors, as determined by: # getconf _NPROCESSORS_ONLN # Example: # threshold = 1.5 # threshold = 9999 # threshold = 0 # threshold = n [LoadMonitor] threshold = n # The [TCPMonitor] section lists all the TCP ports on which to watch for # established connections using netstat(8). It supports both, single TCP # as well as port ranges. # There is no default TCP Monitor. # Examples: # ssh = 22 # http = 80 # https = 443 # other = 64500-65000 [TCPMonitor] #ssh = 22 # The [UDPMonitor] section lists all the UDP ports on which to listen # for data. # Each item listed will BIND a UDP port and listen to any data. Keep # in mind that this port will be bined and no other application will # be able to use this port. # There is no default UDP Monitor. # Examples: # udp-1 = 1025 # udp-2 = 2048 [UDPMonitor] #udp-1025 = 1025 # The [IOMonitor] section lists all the processes to Monitor for IO # activity. A regular expressions is used to find the processes PIDs, which # are later used to monitor IO. # There is no default IO Monitor. # Examples: # kvm-io = "kvm" # mysqld-io = "mysql" [IOMonitor] #kvm-io = "kvm" #mysqld-io = "mysql" # The [InputMonitor] section lists the USB Input devices for which to track # events. Currently, only two types of devices are supported, mouse and keyboard. # Both InputMonitor's are enabled by default. In the case there are no USB # devices connected, PowerNap will ignore these settings. # To disable, set them to "n" or "no", or simply comment them. # Examples: # keyboard = n # keyboard = y [InputMonitor] keyboard = y mouse = y # The [DiskMonitor] section lists the disk devices for which to track # standby/sleep status. If any of the devices are active/idle the # system will be deemed 'active' and will not powernap. Generally useful # for monitoring data drives (e.g. NAS), but will not typically work to # monitor the root drive. Note also that this plugin only reacts to the # state of the drive and does not modify the behavior of the drive # directly. Therefore it only makes sense to monitor a drive that has # already been configured to standby or sleep. # To disable checking specific drives, set them to "n" or "no", # or simply comment them. # Examples: # sda = y # sdb = n [DiskMonitor] #sda = y powernap-2.18/powernap/0000775000175000017500000000000012064361217015376 5ustar roaksoaxroaksoaxpowernap-2.18/powernap/monitors/0000775000175000017500000000000012064361217017250 5ustar roaksoaxroaksoaxpowernap-2.18/powernap/monitors/LoadMonitor.py0000664000175000017500000000274112064361217022055 0ustar roaksoaxroaksoax# powernapd plugin - Monitors system load # # Copyright (C) 2011 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . import os, multiprocessing from logging import error, debug, info, warn class LoadMonitor(): # Initialise def __init__(self, config): self._type = config['monitor'] self._name = config['name'] self._threshold = config['threshold'] self._absent_seconds = 0 # Check system load def active(self): t = self._threshold if t == "n": t = multiprocessing.cpu_count() if os.getloadavg()[0] > float(t): return True return False def start(self): pass # ########################################################################### # Editor directives # ########################################################################### # vim:sts=4:ts=4:sw=4:et powernap-2.18/powernap/monitors/TCPMonitor.py0000664000175000017500000000371112064361217021622 0ustar roaksoaxroaksoax# powernapd plugin - Monitors network for open tcp connections # # Copyright (C) 2011 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . import os, re, commands from logging import error, debug, info, warn # True if an network connection matches def find_connection(netstat, regexes): for regex in regexes: for str in netstat: if regex.search(str): return True return False class TCPMonitor(): # Initialise def __init__(self, config): self._type = config['monitor'] self._name = config['name'] self._absent_seconds = 0 self._regexes = [] port_start = int(config['port'].split("-")[0].strip()) port_end = int(config['port'].split("-")[-1].strip()) + 1 # Add one to use correctly in range for port in range(port_start, port_end): self._regexes.append(re.compile("^tcp.*\W.*:%s\W.*ESTABLISHED$" % port)) # Check for connections def active(self): ps = commands.getoutput("netstat -Wnt").splitlines() if find_connection(ps, self._regexes): return True return False def start(self): pass # ########################################################################### # Editor directives # ########################################################################### # vim:sts=4:ts=4:sw=4:et powernap-2.18/powernap/monitors/Monitor.py0000664000175000017500000000444612064361217021261 0ustar roaksoaxroaksoax# powernapd plugin - Abastract monitor class # # Copyright (C) 2009 Canonical Ltd. # # Authors: Dustin Kirkland # Adam Sutton # # 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, version 3 of the License. # # 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, see . from logging import error, debug, info, warn import time # Abstract monitor # Note: it is not required that you subclass this, merely that you # provide a matching API (all functions are optional) class Monitor ( object ): # Initialise the object def __init__ ( self, config ): self._name = self.__repr__() self._activity = 0 self._grace = 0 self._period = 60.0 if ( config.has_key('name') ): self._name = config['name'] if ( config.has_key('grace') ): self._grace = config['grace'] if ( config.has_key('absent') ): self._period = config['absent'] self.reset() # String representation for debug def __str__ ( self ): return self._name # Reset monitor (usually after resume) def reset ( self ): self._activity = time.time() # Check if monitored resource is active def active ( self): ret = False inactive = time.time() - self._activity if ( inactive < self._period ): debug('%s - inactive for %0.2f secs' % (str(self), inactive)) ret = True return ret # Get preferred grace period def grace ( self ): return self._grace # Start the monitor def start ( self ): pass # Stop the monitor def stop ( self ): pass # ########################################################################### # Editor directives # ########################################################################### # vim:sts=4:ts=4:sw=4:et powernap-2.18/powernap/monitors/ProcessMonitor.py0000664000175000017500000000327412064361217022616 0ustar roaksoaxroaksoax# powernapd plugin - Monitors process table for presence of process # # Copyright (C) 2011 Canonical Ltd. # # Authors: Dustin Kirkland # Andres Rodriguez # # 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, version 3 of the License. # # 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, see . import os, re, commands from logging import error, debug, info, warn # Find list of PIDs that match a given regex (cmdline) def find_process(ps, regex): for str in ps: if regex.search(str): return 1 return 0 class ProcessMonitor(): # Initialise def __init__(self, config): self._type = config['monitor'] self._name = config['name'] self._regex = re.compile(config['regex']) self._absent_seconds = 0 # Check for PIDs def active(self): ps = commands.getoutput("ps -eo args").splitlines() if find_process(ps, self._regex): return True return False def start(self): pass # ########################################################################### # Editor directives # ########################################################################### # vim:sts=4:ts=4:sw=4:et powernap-2.18/powernap/monitors/InputMonitor.py0000664000175000017500000000742212064361217022276 0ustar roaksoaxroaksoax# powernapd plugin - Monitors /dev/input for user activity # # Copyright (C) 2010, 2011 Canonical Ltd. # # Authors: Dustin Kirkland # Adam Sutton # Andres Rodriguez # # 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, version 3 of the License. # # 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, see . import os, re, threading import select from fcntl import fcntl, F_NOTIFY, DN_CREATE, DN_DELETE, DN_MULTISHOT from logging import error, debug, info, warn # Monitor plugin # Monitors devices in /dev/input for activity class InputMonitor ( threading.Thread ): # Initialise def __init__ ( self, config ): threading.Thread.__init__(self) self._type = config['monitor'] self._name = config['name'] self._absent_seconds = 0 self._input_received = False # If regex is in the way of by-id/regex, then path is changed to /dev/input/by-id if os.path.split(config['regex'])[0]: self._path = os.path.join("/dev/input", os.path.dirname(config['regex'])) self._regex = re.compile(os.path.basename(config['regex'])) elif config["regex"] == "kbd": self._path = "/dev/input/by-id" self._regex = re.compile(config['regex']) else: self._path = "/dev/input" self._regex = re.compile(config['regex']) # Register for directory events / setup input watches self._inputs = {} self._poll = select.poll() self._update_inputs() self._dd = os.open(self._path, 0) fcntl(self._dd, F_NOTIFY, DN_DELETE | DN_CREATE | DN_MULTISHOT) # Update the input events list def _update_inputs ( self ): events = {} event = None # Name of the event to poll, after finding it evpath = None # Absolute path of the event to poll # Search for the event in path: for str in os.listdir(self._path): match = self._regex.search(str) if match: event = str evpath = os.path.abspath(os.path.join(self._path, event)) break # If event is different from None, then update! if event: if os.path.exists(evpath): fp = open(evpath) events[evpath] = fp # Register the event to poll self._poll.register(fp.fileno(), select.POLLIN|select.POLLPRI) self._inputs = events # Start the thread def start ( self ): self._running = True threading.Thread.start(self) # Stop thread def stop ( self ): self._running = False # Monitor /dev/input def run ( self ): # Poll for events while self._running: res = self._poll.poll(1000) if ( res ): for fd, e in res: if e & (select.POLLIN|select.POLLPRI): os.read(fd, 32768) # Read what is there! self._input_received = True def active(self): if self._input_received: self._input_received = False return True return False # ########################################################################### # Editor directives # ########################################################################### # vim:sts=4:ts=4:sw=4:et powernap-2.18/powernap/monitors/IOMonitor.py0000664000175000017500000001041112064361217021476 0ustar roaksoaxroaksoax# powernapd plugin - Monitors process table for process with IO activity # # Copyright (C) 2010, 2011 Canonical Ltd. # # Authors: Dustin Kirkland # Adam Sutton # Andres Rodriguez # # 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, version 3 of the License. # # 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, see . import re from logging import error, debug, info, warn, os #from Monitor import Monitor # Monitor plugin # looks for processes that have IO activity. Useful for some server # processes that are always present in the process list even when idle # Looks for the process regex in /proc//cmdline to obtain its PID(s). # Optimal for processes that have a command line. def find_pids_cmdline(regex): ret = [] for d in os.listdir('/proc'): try: path = '/proc/%s/cmdline' % d if os.path.isfile(path): fp = open(path) cmdline = fp.read() fp.close() if regex.search(cmdline): ret.append(int(d)) except: pass return ret # Looks for the process regex in the "Name:" filed of /proc//status # to obtain its PID(s). Optimal for processes that do NOT have a command # line. (i.e. NFS daemon processes.) def find_pids_status(regex): ret = [] for d in os.listdir('/proc'): try: path = '/proc/%s/status' % d if os.path.isfile(path): fp = open(path) status = fp.readline() fp.close() if regex.search(status.split()[1]): ret.append(int(d)) except: pass return ret class IOMonitor (): # Initialise def __init__ ( self, config ): self._iocounts = {} self._type = config['monitor'] self._name = config["name"] self._regex = re.compile(config['regex']) self._absent_seconds = 0 def start(self): pass def active(self): if self.get_io_count(): return True return False # Check for activity def get_io_count ( self ): # Get new PID list from processes with command line. pids = find_pids_cmdline(self._regex) # Processes with no command line result on an empty PID list. # if so, use alternate search method. if not pids: pids = find_pids_status(self._regex) # Get IO counts for all PIDs io_counts = {} for pid in pids: io_counts[pid] = {} try: fp = open('/proc/%d/io' % pid) for l in fp.readlines(): pts = l.split(':') io_counts[pid][pts[0].strip()] = int(pts[1].strip()) fp.close() except: pass # its possible the proc will die in here! ioactivity = False for pid in pids: # New process (assume activity) if pid not in self._iocounts: debug(' %s - adding new PID %d to list' % (self, pid)) # Existing: check for change else: if (self._iocounts[pid]["write_bytes"] != io_counts[pid]["write_bytes"]) or \ (self._iocounts[pid]["read_bytes"] != io_counts[pid]["read_bytes"]): ioactivity = True self._iocounts[pid] = io_counts[pid] break # Update count self._iocounts[pid] = io_counts[pid] if ioactivity: return True return False # ########################################################################### # Editor directives # ########################################################################### # vim:sts=4:ts=4:sw=4:et powernap-2.18/powernap/monitors/ConsoleMonitor.py0000664000175000017500000000413012064361217022572 0ustar roaksoaxroaksoax# powernapd plugin - Monitors process table for presence of process # # Copyright (C) 2011 Canonical Ltd. # # Authors: Dustin Kirkland # Andres Rodriguez # # 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, version 3 of the License. # # 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, see . import os, re, commands, time from logging import error, debug, info, warn # Check /dev/*, such that we don't powernap the system if someone # is actively using a terminal device def get_console_activity(): ptmx = "/dev/ptmx" time = os.stat(ptmx).st_mtime irqs = get_interrupts() return time, irqs # Obtain the interrupts at any given point in time def get_interrupts(): interrupts = 0 f = open("/proc/interrupts", "r") for line in f.readlines(): items = line.split() source = items.pop() if source == "i8042" or source == "keyboard" or source == "mouse": items.pop(0) items.pop() for i in items: interrupts += int(i) f.close() return interrupts class ConsoleMonitor(): # Initialise def __init__(self, config): self._type = config['monitor'] self._name = config['name'] self._absent_seconds = 0 self._time, self._irqs = get_console_activity() # Check for PIDs def active(self): cur_time, cur_irqs = get_console_activity() if cur_time > self._time or cur_irqs > self._irqs: self._irqs = cur_irqs self._time = cur_time return True return False def start(self): pass powernap-2.18/powernap/monitors/UDPMonitor.py0000664000175000017500000000537512064361217021634 0ustar roaksoaxroaksoax# powernapd plugin - Monitors a UDP socket for data # # Copyright (C) 2011 Canonical Ltd. # # Authors: Dustin Kirkland # Adam Sutton # Andres Rodriguez # # 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, version 3 of the License. # # 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, see . import threading, time from logging import error, debug, info, warn # Monitor plugin # listen for data on a UDP socket (typically WOL packets) class UDPMonitor (threading.Thread): # Initialise def __init__ ( self, config ): threading.Thread.__init__(self) self._type = config['monitor'] self._name = config['name'] self._port = config['port'] self._running = False self._data_received = False self._absent_seconds = 0 # Start thread def start ( self ): self._running = True threading.Thread.start(self) # Stop thread def stop ( self ): self._running = False # Open port and wait for data (any data will trigger the monitor) def run ( self ): import socket # Create socket sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) listen = False while self._running: if not listen: try: debug('%s - configure socket' % self) sock.bind(('', self._port)) sock.settimeout(1.0) listen = True except Exception, e: error('%s - failed to config socket [e=%s]' % (self, str(e))) time.sleep(1.0) else: try: # Wait for data sock.recvfrom(1024) self._data_received = True debug('%s - data packet received' % self) self.reset() except: pass # timeout def active(self): if self._data_received: self._data_received = False return True return False # ########################################################################### # Editor directives # ########################################################################### # vim:sts=4:ts=4:sw=4:et powernap-2.18/powernap/monitors/WoLMonitor.py0000664000175000017500000001046512064361217021701 0ustar roaksoaxroaksoax# powernapd plugin - Monitors a UDP socket for data # # Copyright (C) 2011 Canonical Ltd. # # Authors: Dustin Kirkland # Andres Rodriguez # # 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, version 3 of the License. # # 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, see . import threading, time, socket, os, re, struct, traceback from logging import error, debug, info, warn # Obtain MAC address from Monitor Interface def get_mac_address(iface): file = "/sys/class/net/%s/address" % iface f = open(file, 'r') iface = f.read() f.close return iface.strip() # Generate WoL data for local interface to compare with received packet (Partially taken from powerwake) def get_local_wol_data(mac): nonhex = re.compile('[^0-9a-fA-F]') mac = nonhex.sub('', mac) if len(mac) != 12: error("Malformed mac address [%s]" % mac) data = ''.join(['FFFFFFFFFFFF', mac * 16]) wol_data = '' for i in range(0, len(data), 2): wol_data = ''.join([wol_data, struct.pack('B', int(data[i: i + 2], 16))]) return wol_data # Obtain a list of available eth's, with its MAC address and WoL data. def get_eths_mac_wol_info(): ifaces = [] prefix = re.compile("eth") dirs = os.listdir("/sys/class/net") for iface in dirs: if prefix.search(iface): # Obtain MAC address mac = get_mac_address(iface) # Obtain WoL data of eth data = get_local_wol_data(mac) ifaces.append({"iface":iface, "mac":mac, "wol":data}) return ifaces # Monitor plugin # listen for WoL data in a UDP socket. It compares if the data is specifically # for any of the interfaces class WoLMonitor (threading.Thread): # Initialise def __init__ ( self, config ): threading.Thread.__init__(self) self._type = config['monitor'] self._name = config['name'] self._port = config['port'] self._host = '' # Bind to all Interfaces self._running = False self._data_received = False self._absent_seconds = 0 # Start thread def start ( self ): self._running = True threading.Thread.start(self) # Stop thread def stop ( self ): self._running = False # Open port and wait for data (any data will trigger the monitor) def run ( self ): isRunning = False #self._port = 7 ifaces = get_eths_mac_wol_info() # Prepare the socket and bind port s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: s.bind((self._host, self._port)) isRunning = True except: #error("Unable to bind port [%s]" % port) return #while isRunning: while self._running: try: #debug(logging.DEBUG, " WoL monitor started at port [%s]" % port) recv_wol_msg, address = s.recvfrom(1024) #debug(logging.DEBUG, " WoL packet received from %s" % address[0]) for iface in ifaces: if recv_wol_msg == iface["wol"]: #debug(logging.DEBUG, " WoL data matches local interface [%s]" % iface["iface"]) self._data_received = True #isRunning = False # TODO: Should return signal to daemon and wake up??? #break except (KeyboardInterrupt, SystemExit): raise except: traceback.print_exc() def active(self): if self._data_received: self._data_received = False return True return False # ########################################################################### # Editor directives # ########################################################################### # vim:sts=4:ts=4:sw=4:et powernap-2.18/powernap/monitors/__init__.py0000664000175000017500000000000012064361217021347 0ustar roaksoaxroaksoaxpowernap-2.18/powernap/monitors/DiskMonitor.py0000664000175000017500000000471712064361217022075 0ustar roaksoaxroaksoax# powernapd plugin - Monitors disk power state # # Copyright (C) 2011 Jim Heck. # # Authors: Jim Heck # # 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, version 3 of the License. # # 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, see . import re, commands from logging import error, debug, info, warn # Monitor plugin # looks for disks that are active/idle. Useful for sleeping only when # specified disks are in standby class DiskMonitor (): # Initialise def __init__(self, config): self._type = config['monitor'] self._name = config['name'] self._regex_state = re.compile(r"^\s+drive\s+state\s+is:\s+(\S+)") self._regex_not_found = re.compile(r"^.*No\s+such\s+file") self._absent_seconds = 0 def start(self): pass def active(self): if self.is_disk_active(): return True return False # Check for inactive drive by looking explicitly for drive state of # 'standby' or 'sleeping'. Assume 'active/idle', except in case # where fuction returns 'No such file' error (e.g. unknown drive) def is_disk_active(self): hdparm = commands.getoutput("hdparm -C /dev/%s" % self._name).splitlines() is_active = True for line in hdparm: if self._regex_not_found.match(line): #warn(" Disk monitor: disk %s not found, ignoring" % self._name) return False if self._regex_state.match(line): state = self._regex_state.search(line).group(1) #debug(" Disk monitor: disk %s in state %s" % (self._name, state)) if state == 'standby' or state == 'sleeping': is_active = False if is_active: return True return False # ########################################################################### # Editor directives # ########################################################################### # vim:sts=4:ts=4:sw=4:et powernap-2.18/powernap/powernap.py0000664000175000017500000002002112064361217017576 0ustar roaksoaxroaksoax#!/usr/bin/python # # powernap.py - handles powernap's config and initializes Monitors. # # Copyright (C) 2010 Canonical Ltd. # # Authors: Andres Rodriguez # # 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, version 3 of the License. # # 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, see . import ConfigParser, sys, re, os from monitors import ProcessMonitor, LoadMonitor, InputMonitor, TCPMonitor, UDPMonitor, IOMonitor, WoLMonitor, ConsoleMonitor, DiskMonitor class PowerNap: def __init__(self): self.PKG = "powernap" self.CONFIG = "/etc/powernap/config" self.ACTION = "/usr/sbin/powernap" self.RECOVER_ACTION = "/usr/sbin/pm-powersave false" self.ABSENT_SECONDS = sys.maxint self.STAGE2_ABSENT_SECONDS = sys.maxint self.INTERVAL_SECONDS = int(1) self.GRACE_SECONDS = int(60) self.DEBUG = int(0) self.ACTION_METHOD = 0 self.STAGE2_ACTION_METHOD = 4 self.MONITORS = [] self.WARN = False self.WATCH_CONFIG = False self.KERN_MODULES = {} self.SERVICES = {} self.stage2_action_enabled = False # Load default config file (/etc/powernap/config) self.load_config_file() def load_config_file(self): stage2_section = "%s-stage2" % self.PKG cfg = ConfigParser.ConfigParser() cfg.read(self.CONFIG) try: # Load items in DEFAULT section defaults = cfg.items(self.PKG) for items in defaults: self.set_default_values(items[0], items[1]) stage2 = cfg.items(stage2_section) for items in stage2: self.set_stage2_values(items[0], items[1]) # Load items on each monitor monitors_config = cfg.sections() for monitor in monitors_config: if monitor not in [self.PKG, stage2_section]: for items in cfg.items(monitor): self.load_monitors_config(monitor, items) except: pass # Load extra config files (/etc/powernap/config.d/*) configd = "/etc/%s/config.d" % self.PKG if os.path.exists(configd): for config in os.listdir(configd): self.load_configd_files("%s/%s" % (configd, config)) def load_configd_files(self, config_file): cfg = ConfigParser.ConfigParser() cfg.read(config_file) try: monitors_config = cfg.sections() for monitor in monitors_config: for items in cfg.items(monitor): for i in range(len(self.MONITORS)): if self.MONITORS[i]['monitor'] == monitor and self.MONITORS[i]['name'] == items[0]: self.MONITORS.pop(i) break self.load_monitors_config(monitor, items) except: pass def set_default_values(self, var, value): if var == "absent_seconds": self.ABSENT_SECONDS = eval(value) if var == "interval_seconds": self.INTERVAL_SECONDS = eval(value) if var == "grace_seconds": self.GRACE_SECONDS = eval(value) if var == "debug": self.DEBUG = eval(value) if var == "action": self.ACTION = eval(value) if var == "action_method": self.ACTION_METHOD = eval(value) if var == "warn": if value == "y" or value == "yes": self.WARN = True else: self.WARN = False if var == "watch_config": if value == "y" or value == "yes": self.WATCH_CONFIG = True else: self.WATCH_CONFIG = False if var == "kern_modules": self.KERN_MODULES = value.split() if var == "services": self.SERVICES = value.split() def set_stage2_values(self, var, value): if var == "stage2_action_method": self.STAGE2_ACTION_METHOD = eval(value) if var == "stage2_absent_seconds": self.STAGE2_ABSENT_SECONDS = eval(value) if self.STAGE2_ABSENT_SECONDS > 0: self.stage2_action_enabled = True def usb_input_available(self, event): regex = re.compile(event) path = "/dev/input/by-id" exists = False for str in os.listdir(path): match = regex.search(str) if match: exists = True break return exists def load_monitors_config(self, monitor, items): if monitor == "ProcessMonitor" or monitor == "IOMonitor": self.MONITORS.append({"monitor":monitor, "name":items[0], "regex":eval(items[1]), "absent":self.ABSENT_SECONDS}) if monitor == "InputMonitor" and (items[1] == "y" or items[1] == "yes"): if items[0] == "mouse" and self.usb_input_available("mouse"): self.MONITORS.append({"monitor":monitor, "name":items[0], "regex":"mice"}) elif items[0] == "keyboard" and self.usb_input_available("kbd"): self.MONITORS.append({"monitor":monitor, "name":items[0], "regex":"kbd"}) #else: # self.MONITORS.append({"monitor":monitor, "name":items[0], "regex":items[1]}) if monitor == "ConsoleMonitor" and (items[1] == "y" or items[1] == "yes"): self.MONITORS.append({"monitor":monitor, "name":items[0]}) if monitor == "LoadMonitor": self.MONITORS.append({"monitor":monitor, "name":items[0], "threshold":items[1]}) if monitor == "TCPMonitor": self.MONITORS.append({"monitor":monitor, "name":items[0], "port":items[1], "absent":self.ABSENT_SECONDS}) if monitor == "UDPMonitor": # If ACTION_METHOD is 0 (PowerSave) and port is 7 or 9, do *NOT* create a monitor # This will cause that the WoL monitor to not be able to bind the port or viceversa. # TODO: Display a message that port is not being binded!! if self.ACTION_METHOD == 0 and (items[1] != 7 or items[1] != 9): self.MONITORS.append({"monitor":monitor, "name":items[0], "port":eval(items[1]), "absent":self.ABSENT_SECONDS}) if monitor == "WoLMonitor": self.MONITORS.append({"monitor":monitor, "name":items[0], "port":eval(items[1]), "absent":self.ABSENT_SECONDS}) if monitor == "DiskMonitor" and (items[1] == "y" or items[1] == "yes"): self.MONITORS.append({"monitor":monitor, "name":items[0], "absent":self.ABSENT_SECONDS}) def get_monitors(self): monitor = [] for config in self.MONITORS: if config["monitor"] == "ProcessMonitor": p = ProcessMonitor.ProcessMonitor(config) if config["monitor"] == "LoadMonitor": p = LoadMonitor.LoadMonitor(config) if config["monitor"] == "UDPMonitor": p = UDPMonitor.UDPMonitor(config) if config["monitor"] == "WoLMonitor": p = WoLMonitor.WoLMonitor(config) if config["monitor"] == "InputMonitor": p = InputMonitor.InputMonitor(config) if config["monitor"] == "ConsoleMonitor": p = ConsoleMonitor.ConsoleMonitor(config) if config["monitor"] == "IOMonitor": p = IOMonitor.IOMonitor(config) if config["monitor"] == "TCPMonitor": p = TCPMonitor.TCPMonitor(config) if config["monitor"] == "DiskMonitor": p = DiskMonitor.DiskMonitor(config) monitor.append(p) return monitor powernap-2.18/powernap/__init__.py0000664000175000017500000000000012064361217017475 0ustar roaksoaxroaksoaxpowernap-2.18/bin/0000775000175000017500000000000012064361217014313 5ustar roaksoaxroaksoaxpowernap-2.18/bin/powernap_calculator0000775000175000017500000000656312064361217020317 0ustar roaksoaxroaksoax#!/usr/bin/python # # powernap_calculator - estimate power savings using statistcal analysis # Copyright (C) 2009 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . import getopt import sys # command line options short_opts = 'h:p:g:' long_opts = ['hosts=', 'guests-per-host=', 'guests='] usage_string = "Usage:\n powernap_calculator [-h|--hosts NUM] [-p|--guests-per-host NUM] [-g|--guests NUM]" if len(sys.argv) != 7: print(usage_string) exit(1) # parse getopt options try: opts, args = getopt.getopt(sys.argv[1:], short_opts, long_opts) for k, v in opts: if k in ('-h', '--hosts'): hosts = int(v) elif k in ('-p', '--guests-per-host'): guests_per_host = int(v) elif k in ('-g', '--guests'): guests = int(v) else: print(usage_string) exit(1) except: print(usage_string) exit(1) # convert an input num to a different base with each # digit as an element in the list; # ensure that the sum of the digits equals the number of guests; # return the list representing the way vm's are allocated across hosts def vm_allocations(num, base, hosts, guests): list = [0]*hosts i = 0 while num != 0: remainder = num % base list[i] = remainder i += 1 num = num / base if sum(list) == guests: return list else: return -1 # count the number of zero's found in the list def count_zeros(list): count = 0 for i in list: if i == 0: count += 1 return count print("Calculating...\n ") # this might be a *very* big number upper_limit = (guests_per_host+1)**hosts zeros = [0]*(hosts + 1) total = 0 num = 0 # brute force all possible combinations while num < upper_limit: # determine the associated vm_allocations for this particular index list = vm_allocations(num, guests_per_host+1, hosts, guests) if list != -1: # count the zeros in this list c = count_zeros(list) zeros[c] += 1 total += 1 # print a helpful running percent-done if num % 100000 == 0: print("\b\b\b\b\b\b\b\b\b\b%.3f%% " % (100.*num/upper_limit)) num += 1 print("\nIn a cloud with [%d] hosts, which can handle [%d] guests-per-host, currently running [%d] guests,\nyou may expect the following:\n" % (hosts, guests_per_host, guests)) expected_savings = 0 #print zeros # do the calculations for i in range(0, len(zeros)): if zeros[i] > 0: probability = 1. * zeros[i] / total if probability > 0 and probability < .01: pstr = "<1" else: pstr = "%.1f" % (100. * probability) savings = 100.*i/hosts print("[%5s%%] likely that [%d/%d] of your hosts would powernap, for a [%.0f%%] power savings" % (pstr, i, hosts, savings)) expected_savings += probability * savings print("\nThe overall expected value is [%.1f%%] power savings." % expected_savings) exit(0) powernap-2.18/bin/powerwake0000775000175000017500000001516712064361217016257 0ustar roaksoaxroaksoax#!/usr/bin/python # # powerwake - a smart remote host waking utility, supporting multiple # waking methods, and caching known hostnames and addresses # # Copyright (C) 2009 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . import commands import os import re import socket import struct import sys import getopt global DEBUG, PKG, RC, HOME DEBUG = 0 PKG = "powerwake" RC = 0 HOME = os.getenv("HOME") short_opts = 'hb:m:' long_opts = ['help', 'broadcast=', 'method='] usage_string = "Usage:\n powerwake [-b|--broadcast BROADCAST_IP] [-m|--method METHOD] TARGET_MAC|TARGET_IP|TARGET_HOST" # Generic debug function def debug(level, msg): if DEBUG >= level: print("%s" % msg) # Generic error function def error(msg): debug(0, "ERROR: %s" % msg) ERROR = 1 # Generic warning function def warning(msg): debug(0, "WARNING: %s" % msg) # Generic info function def info(msg): debug(0, "INFO: %s" % msg) def wakeonlan(mac): nonhex = re.compile('[^0-9a-fA-F]') mac = nonhex.sub('', mac) if len(mac) != 12: error("Malformed mac address [%s]" % mac) info("Sending magic packet to: [%s]" % mac) # We should cache this to /var/cache/powerwake/ethers, # in case arp entry isn't available next time data = ''.join(['FFFFFFFFFFFF', mac * 16]) send_data = '' for i in range(0, len(data), 2): send_data = ''.join([send_data, struct.pack('B', int(data[i: i + 2], 16))]) try: sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) sock.sendto(send_data, (broadcast, 7)) except: error("Network is unreachable") def is_ip(ip): r1 = re.compile('^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$') if r1.match(ip): return 1 else: return 0 def is_mac(mac): r1 = re.compile('^[0-9a-fA-F]{12}$') r2 = re.compile('^[0-9a-fA-F]{2}.[0-9a-fA-F]{2}.[0-9a-fA-F]{2}.[0-9a-fA-F]{2}.[0-9a-fA-F]{2}.[0-9a-fA-F]{2}$') if r1.match(mac) or r2.match(mac): return 1 else: return 0 # Source the cached, known arp entries def get_arp_cache(): host_to_mac = {} for file in ["/var/cache/%s/ethers" % PKG, "/etc/ethers", "%s/.cache/ethers" % HOME]: if os.path.exists(file): f = open(file, 'r') for i in f.readlines(): try: (m, h) = i.split() host_to_mac[h] = m except: pass f.close() return host_to_mac # Source the current, working arp table def get_arp_current(host_to_mac): # Load hostnames for i in os.popen("/usr/sbin/arp"): m = i.split()[2] h = i.split()[0] if is_mac(m): host_to_mac[h] = m # Load ip addresses for i in os.popen("/usr/sbin/arp -n"): m = i.split()[2] h = i.split()[0] if is_mac(m): host_to_mac[h] = m return host_to_mac def write_arp_cache(host_to_mac): if not os.access("%s/.cache/" % HOME, os.W_OK): return if not os.path.exists("%s/.cache/" % HOME): os.makedirs("%s/.cache/" % HOME) f = open("%s/.cache/ethers" % HOME, 'a') f.close() for file in ["/var/cache/%s/ethers" % PKG, "%s/.cache/ethers" % HOME]: if os.access(file, os.W_OK): f = open(file, 'w') for h in host_to_mac: if is_mac(host_to_mac[h]): f.write("%s %s\n" % (host_to_mac[h], h)) f.close() def get_arp_hash(): host_to_mac = get_arp_cache() host_to_mac = get_arp_current(host_to_mac) write_arp_cache(host_to_mac) return host_to_mac # TODO: # Parameters to add: # --list - list known mac/ip-host combinations # --clear - clear the cache if __name__ == '__main__': # set up defaults broadcast = '' method = 'wol' # parse getopt options try: opts, args = getopt.getopt(sys.argv[1:], short_opts, long_opts) except: print(usage_string) exit(1) for name, value in opts: if name in ('-b', '--broadcast'): if is_ip(value): broadcast = value else: error("Value passed to " + name + " is not a valid broadcast address [%s]" % value) print(usage_string) exit(1) elif name in ('-m', '--method'): method = value elif name in ('-h', '--help'): print(usage_string) exit(0) # if args is less than one, we don't have a host to wake up if len(args) < 1: error("Please provide one or more MAC addresses, IP addresses, or Hostnames") print(usage_string) exit(1) # Process command line parameters for i in args: # If parameter matches a system with a static configuration, use it! # ^^^ Not yet implemented, default to wake-on-lan method for now if method == "wol": if is_mac(i): # this appears to be a mac address, just use it m = i pass else: # Retrieve the mac cache host_to_mac = get_arp_cache() if host_to_mac.has_key(i): # mac found in the hash info("Trying to wake host: [%s]" % i) m = host_to_mac[i] else: # not in the cache, do the expensive arp search host_to_mac = get_arp_hash() if host_to_mac.has_key(i): # mac found in the hash info("Trying to wake host: [%s]" % i) m = host_to_mac[i] else: # cannot autodetect the mac address error("Could not determine the MAC address of [%s]" % i) continue if is_mac(m): wakeonlan(m) else: error("Could not wake host [%s]" % m) else: error("Unsupported method [%s]" % method) RC=1 sys.exit(RC) powernap-2.18/action0000664000175000017500000000141412064361217014743 0ustar roaksoaxroaksoax#!/bin/sh # # If the file [ /etc/powernap/action ] is executable, then the # /usr/sbin/powernap binary will run it when called. # # Otherwise, /usr/sbin/powernap will run one of: # * pm-suspend # * pm-hibernate # * poweroff # depending on your hardware's capabilities, as determined by # pm-is-supported(1). # # You may do one of: # 1) Write your own custom script below and make this file executable, # calling some specific action, such as: # /usr/sbin/pm-suspend # /usr/sbin/pm-hibernate # /sbin/poweroff # echo 'I am wasting electricity' | mail Al_Gore@example.com # 2) Replace this file with an executable script or binary # 3) Symlink this file to some other executable script or binary # # See powernap(1) for more information. powernap-2.18/sbin/0000775000175000017500000000000012064361217014476 5ustar roaksoaxroaksoaxpowernap-2.18/sbin/powernap-action0000775000175000017500000001154312064361217017536 0ustar roaksoaxroaksoax#!/usr/bin/python # # powernap-action - enable or disable actions when running powernap # Available actions at /usr/lib/powernap/actions. # Enabled actions at /etc/powernap/actions.d. # # Copyright (C) 2010 Canonical Ltd. # # Authors: Andres Rodriguez # # 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, version 3 of the License. # # 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, see . import os, sys, commands from optparse import OptionParser global PKG PKG = "powernap" PM_ACTIONS_DIR = "/etc/pm/power.d" # If not running as root, exit program and display message if not os.geteuid()==0: sys.exit("This utility may only be run by the root user.") # Check if action exists. def action_exists(action): path = "%s/%s" % (PM_ACTIONS_DIR, action) if os.path.exists(path): return True else: return False # Check if action is enabled. def is_action_enabled(action): path = "%s/%s" % (PM_ACTIONS_DIR, action) if os.access(path, os.X_OK): return True else: return False def do_action_enable(action): src = "%s/%s" % (PM_ACTIONS_DIR, action) info("enabling action [%s]..." % action) os.chmod(src, 0755) def do_action_disable(action): path = "%s/%s" % (PM_ACTIONS_DIR, action) info("disabling action [%s]..." % action) #TODO: Not only remove, but undo changes if possible!! os.chmod(path, 0644) def list_available_actions(): #TODO: Display the actions and show which ones are enabled or disabled. try: actionslist = os.listdir(PM_ACTIONS_DIR) for action in actionslist: path = "%s/%s" % (PM_ACTIONS_DIR, action) (status, output) = commands.getstatusoutput("%s help" % path) if os.access(path, os.X_OK): print "[enabled] %-20s - %s" % (action, output) else: print "[disabled] %-20s - %s" % (action, output) except: error("Could not retrieve list of available actions") def get_action_status(): print "obtaining status of" def info(str): print("INFO: %s" % str) def error(str): print("ERROR: %s" % str) sys.exit(1) if __name__ == '__main__': hasOptions = False # Option Parser usage = "usage: %prog \n\ \n\ %prog is a utility that allows to enable and disable available PowerNap\n\ actions.\n\ \n\ %prog --enable [action]\n\ %prog --disable [action]\n\ %prog --list" parser = OptionParser(usage) parser.add_option('-e', '--enable', action='store', type='string', dest='enable', help='enable available PowerNap actions', metavar='ACTION') parser.add_option('-d', '--disable', action='store', type='string', dest='disable', help='disable available PowerNap actions', metavar='ACTION') parser.add_option('-l', '--list', action='store_true', dest='list', help='Lists available actions') (opt, args) = parser.parse_args() if opt.list and opt.enable: error("Options -l (--list) and -e (--enable) are mutually exclusive") sys.exit(1) if opt.list and opt.disable: error("Options -l (--list) and -d (--disable) are mutually exclusive") if opt.enable and opt.disable: error("Options -e (--enable) and -d (--disable) are mutually exclusive") sys.exit(1) if opt.enable: hasOptions = True # Check if action exists, if not, exit if not action_exists(opt.enable): error("[%s] does not exist, exiting..." % opt.enable) sys.exit(1) # If action is not enabled, enable it, otherwise do nothing. if not is_action_enabled(opt.enable): do_action_enable(opt.enable) else: info("[%s] is already enabled, skipping..." % opt.enable) if opt.disable: hasOptions = True # Check if action exists, if not, exit if not action_exists(opt.disable): error("[%s] does not exist, exiting..." % opt.disable) sys.exit(1) # If action is enabled, disable it, otherwise do nothing. if is_action_enabled(opt.disable): do_action_disable(opt.disable) else: info("[%s] is already disabled, skipping..." % opt.disable) if opt.list: hasOptions = True list_available_actions() if not hasOptions: print parser.get_usage() powernap-2.18/sbin/powernap-now0000775000175000017500000000172612064361217017066 0ustar roaksoaxroaksoax#!/bin/sh -e # # powernap-now - send powernapd the 'now' signal # # Copyright (C) 2010 Canonical Ltd. # # Authors: Dustin Kirkland # # 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, version 3 of the License. # # 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, see . PKG="powernap" PIDFILE=/var/run/$PKG.pid if [ -r $PIDFILE ]; then echo "Sending $PKG the 'now' signal" kill -USR1 $(cat $PIDFILE) exit $? else echo "$PKG does not appear to be running" exit 1 fi powernap-2.18/sbin/powernapd0000775000175000017500000003410012064361217016421 0ustar roaksoaxroaksoax#!/usr/bin/python # # powernapd - monitor a system process table; if IDLE amount of time # goes by with no MONITORED_PROCESSES running, run ACTION # # Copyright (C) 2009-2011 Canonical Ltd. # # Authors: Dustin Kirkland # Andres Rodriguez # # 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, version 3 of the License. # # 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, see . # Imports import commands import logging, logging.handlers import os import re import signal import sys import time import socket, traceback import struct from powernap import powernap # Initialize Powernap. This initialization loads the config file. try: powernap = powernap.PowerNap() #os.putenv("ACTION_METHOD", str(powernap.ACTION_METHOD)) except: print("Unable to initialize PowerNap") sys.exit(1) # Define globals global LOCK, CONFIG, MONITORS LOCK = "/var/run/%s.pid" % powernap.PKG LOG = "/var/log/%s.log" % powernap.PKG POWERSAVE_FLAG = "/var/run/%s/powersave" % powernap.PKG logging.basicConfig(filename=LOG, format='%(asctime)s %(levelname)-8s %(message)s', datefmt='%Y-%m-%d_%H:%M:%S', level=logging.DEBUG,) # Generic debug function def debug(level, msg): if level >= (logging.ERROR - 10*powernap.DEBUG): logging.log(level, msg) # Generic error function def error(msg): debug(logging.ERROR, msg) sys.exit(1) # Lock function, using a pidfile in /var/run def establish_lock(): if os.path.exists(LOCK): f = open(LOCK,'r') pid = f.read() f.close() error("Another instance is running [%s]" % pid) else: try: f = open(LOCK,'w') except: error("Administrative privileges are required to run %s" % powernap.PKG); f.write(str(os.getpid())) f.close() # Set signal handlers signal.signal(signal.SIGHUP, signal_handler) signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGQUIT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) signal.signal(signal.SIGIO, signal.SIG_IGN) #signal.signal(signal.SIGIO, input_singal_handler) signal.signal(signal.SIGUSR1, take_action_handler) signal.signal(signal.SIGUSR2, take_recover_action_handler) # Clean up lock file on termination signals def signal_handler(signal, frame): if os.path.exists(LOCK): os.remove(LOCK) debug(logging.INFO, "Stopping %s" % powernap.PKG) sys.exit(1) # Handler warns users when an USB Input device has been connected or # disconnected. This is only useful for [InputMonitor] to avoid errors. def input_signal_handler(signal, frame): debug(logging.WARNING, "A monitored [InputMonitor] device has been disconnected or reconnected.") # Send a message to system users, that we're about to take an action, # and sleep for a grace period def warn_users(): timestamp = time.strftime("%Y-%m-%d_%H:%M:%S") msg1 = "[%s] PowerNap will take the following action in [%s] seconds: [%s]" % (timestamp, powernap.GRACE_SECONDS, powernap.ACTION) msg2 = "To cancel this operation, press any key in any terminal" debug(logging.WARNING, msg1) if powernap.WARN: commands.getoutput("echo '%s\n%s' | wall" % (msg1, msg2)) # TODO: notify authorities about action taken def notify_authorities(): debug(logging.WARNING, "Taking action [%s]" % powernap.ACTION) # In powersave mode or not? def in_powersave(): global POWERSAVE_FLAG if os.path.exists(POWERSAVE_FLAG): return True else: return False # Basic touch function def touch(fname, times = None): with file(fname, 'a'): os.utime(fname, times) # flag_powersave def flag_powersave(): global POWERSAVE_FLAG touch(POWERSAVE_FLAG) # unflag_powersave def unflag_powersave(): global POWERSAVE_FLAG if os.path.exists(POWERSAVE_FLAG): os.unlink(POWERSAVE_FLAG) # Recover action for ACTION_METHOD=0 (pm-powersave). def take_recover_action(): debug(logging.WARNING, "Taking recover action [%s]" % powernap.RECOVER_ACTION) os.system(powernap.RECOVER_ACTION) unflag_powersave() for monitor in MONITORS: monitor._absent_seconds = 0 if os.path.exists("/var/run/powernap.state"): os.unlink("/var/run/powernap.state") # Re-enable SERVICES/MODULES when waking from PowerSave # TODO: This should probably go into their own executable. if powernap.KERN_MODULES: debug(logging.WARNING, "Re-enabling Kernel Modules") for module in powernap.KERN_MODULES: debug(logging.WARNING, " Module [%s]" % module) os.system("/etc/powernap/actions/kernel_module false %s" % module) if powernap.SERVICES: debug(logging.WARNING, "Re-enabling Services") for service in powernap.SERVICES: debug(logging.WARNING, " Service [%s]" % service) os.system("/etc/powernap/actions/service false %s" % service) debug(logging.DEBUG, "Reseting counters after taking recover action") # Handler for asynchronous external signals def take_recover_action_handler(signal, frame): if powernap.ACTION_METHOD == 0: take_recover_action() # Zero the counters and take the action def take_action(): notify_authorities() debug(logging.DEBUG, "Reseting counters prior to taking action") for monitor in MONITORS: monitor._absent_seconds = 0 os.system("%s %s" % (powernap.ACTION, powernap.ACTION_METHOD)) # Disable MODULES/SERVICES when on PowerSave if defined. # TODO: This should probably go into their own executable. if powernap.ACTION_METHOD == 0: if powernap.KERN_MODULES: debug(logging.WARNING, "Disabling Kernel Modules") for module in powernap.KERN_MODULES: debug(logging.WARNING, " Kernel Module [%s]" % module) os.system("/etc/powernap/actions/kernel_module true %s" % module) if powernap.SERVICES: debug(logging.WARNING, "Disabling Services") for service in powernap.SERVICES: debug(logging.WARNING, " Service [%s]" % service) os.system("/etc/powernap/actions/service true %s" % service) # Handler for asynchronous external signals def take_action_handler(signal, frame): take_action() if powernap.ACTION_METHOD == 0: unflag_powersave() def take_action_stage2(): notify_authorities() debug(logging.DEBUG, "Reseting counters prior to taking action") for monitor in MONITORS: monitor._absent_seconds = 0 os.system("%s %s" % (powernap.ACTION, powernap.STAGE2_ACTION_METHOD)) def powernapd_loop(): # Starting the Monitors for monitor in MONITORS: debug(logging.DEBUG, "Starting [%s:%s]" % (monitor._type, monitor._name)) monitor.start() grace_seconds = powernap.GRACE_SECONDS stage2_grace_seconds = int(powernap.STAGE2_ABSENT_SECONDS/4) unflag_powersave() users_warned = False watch_config_timestamp = os.stat(powernap.CONFIG).st_mtime while 1: if powernap.WATCH_CONFIG == True: if watch_config_timestamp != os.stat(powernap.CONFIG).st_mtime: # TODO: This only reloads general settings. Does not restart monitors. # In the future, this should also stop/start monitors when reloading. debug(logging.WARNING, "Reloading configuration file") powernap.load_config_file() watch_config_timestamp = os.stat(powernap.CONFIG).st_mtime debug(logging.DEBUG, "Sleeping [%d] seconds" % powernap.INTERVAL_SECONDS) time.sleep(powernap.INTERVAL_SECONDS) # Examine monitor activity, compute absent time of each monitored monitor process if in_powersave(): debug(logging.DEBUG, "Examining Monitors - Running in PowerSave mode") else: debug(logging.DEBUG, "Examining Monitors") absent_monitors = 0 grace_monitors = 0 stage2_grace_monitors = 0 stage2_absent_monitors = 0 for monitor in MONITORS: debug(logging.DEBUG, " Looking for [%s] %s" % (monitor._name, monitor._type)) if monitor.active(): monitor._absent_seconds = 0 grace_seconds = powernap.GRACE_SECONDS users_warned = False debug(logging.DEBUG, " Activity found, reset absent time [%d/%d]" % (monitor._absent_seconds, powernap.ABSENT_SECONDS)) if in_powersave() and powernap.ACTION_METHOD == 0: take_recover_action() break elif in_powersave(): # activity during POWERSAVE mode. Only increments absent_seconds and provides logging. monitor._absent_seconds += powernap.INTERVAL_SECONDS debug(logging.DEBUG, " Activity not found, increment absent time [%d/%d]" % (monitor._absent_seconds, powernap.ABSENT_SECONDS)) if powernap.stage2_action_enabled: # second stage absent seconds: If monitor is absent for (STAGE2_ABSENT_SECONDS), # we consider it in second stage for action method if monitor._absent_seconds >= (powernap.STAGE2_ABSENT_SECONDS) and powernap.stage2_action_enabled: stage2_absent_monitors += 1 if monitor._absent_seconds >= (powernap.STAGE2_ABSENT_SECONDS - int(powernap.STAGE2_ABSENT_SECONDS/4)): stage2_grace_monitors += 1 else: # activity not found, increment absent time monitor._absent_seconds += powernap.INTERVAL_SECONDS debug(logging.DEBUG, " Activity not found, increment absent time [%d/%d]" % (monitor._absent_seconds, powernap.ABSENT_SECONDS)) if monitor._absent_seconds >= (powernap.ABSENT_SECONDS - powernap.GRACE_SECONDS): # If monitor is absent for (ABSENT_SECONDS - GRACE_SECONDS), we consider it in GRACE PERIOD. grace_monitors += 1 if monitor._absent_seconds >= powernap.ABSENT_SECONDS: # activity missing for >= absent_seconds threshold, mark absent debug(logging.DEBUG, " Activity absent for >= threshold, so mark absent") absent_monitors += 1 # GRACE PERIOD: Time between ABSENT_SECONDS and (ABSENT_SECONDS - GRACE_SECONDS) # If all monitors are in their own GRACE period if grace_monitors > 0 and grace_monitors == len(MONITORS): if users_warned is False and powernap.ACTION_METHOD != 0: # Only display warn_users() wall message if action is something other than # powersave, and only when initially entering to GRACE_PERIOD. # If in GRACE_PERIOD but a warn_users() already issued, then ignore condition. warn_users() users_warned = True debug(logging.WARNING, "Entered into GRACE PERIOD. Action [%s] will be taken in [%d] seconds" % (powernap.ACTION, grace_seconds)) grace_seconds -= powernap.INTERVAL_SECONDS if grace_seconds == -1: # Reset flags to original if powerwake finished GRACE PERIOD and ready to take action grace_seconds = powernap.GRACE_SECONDS users_warned = False # Determine if action needs to be taken if absent_monitors > 0 and absent_monitors == len(MONITORS): take_action() # If ACTION_METHOD is PowerSave then flag. Use is when tracking Monitor Activity if powernap.ACTION_METHOD == 0: flag_powersave() if powernap.stage2_action_enabled: if stage2_grace_monitors > 0 and stage2_grace_monitors == len(MONITORS): if users_warned is False: warn_users() users_warned = True debug(logging.WARNING, "Second Stage Action [%s] will be taken in [%d] seconds" % (powernap.ACTION, stage2_grace_seconds)) stage2_grace_seconds -= powernap.INTERVAL_SECONDS if stage2_grace_seconds == -1: stage2_grace_seconds = int(powernap.STAGE2_ABSENT_SECONDS/4) users_warned = False if in_powersave() and stage2_absent_monitors > 0 and stage2_absent_monitors == len(MONITORS): unflag_powersave() take_action_stage2() # "Forking a Daemon Process on Unix" from The Python Cookbook def daemonize (stdin="/dev/null", stdout="/var/log/%s.log" % powernap.PKG, stderr="/var/log/%s.err" % powernap.PKG): try: pid = os.fork() if pid > 0: sys.exit(0) except OSError, e: sys.stderr.write("fork #1 failed: (%d) %sn" % (e.errno, e.strerror)) sys.exit(1) os.chdir("/") os.setsid() try: pid = os.fork() if pid > 0: sys.exit(0) except OSError, e: sys.stderr.write("fork #2 failed: (%d) %sn" % (e.errno, e.strerror)) sys.exit(1) f = open(LOCK,'w') f.write(str(os.getpid())) f.close() for f in sys.stdout, sys.stderr: f.flush() si = file(stdin, 'r') so = file(stdout, 'a+') se = file(stderr, 'a+', 0) os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) # Main program if __name__ == '__main__': # Ensure that only one instance runs establish_lock() daemonize() try: # Run the main powernapd loop MONITORS = powernap.get_monitors() debug(logging.INFO, "Starting %s" % powernap.PKG) powernapd_loop() finally: # Clean up the lock file if os.path.exists(LOCK): os.remove(LOCK) powernap-2.18/sbin/powerwake-monitor0000775000175000017500000001337612064361217020127 0ustar roaksoaxroaksoax#!/usr/bin/python # # Copyright (C) 2011 Canonical Ltd. # # Authors: Andres Rodriguez # # 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, version 3 of the License. # # 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, see . import os, sys, commands from optparse import OptionParser from powerwake import powerwake global PKG PKG = "powerwake-monitor" # If not running as root, exit program and display message if not os.geteuid()==0: sys.exit("This utility may only be run by the root user.") def error(error): print " ERROR: %s" % error sys.exit(1) def info(info): print " INFO: %s" % info # Add IP to monitor def add_host_to_monitor(powerwake, host, macaddr, monitor): # obtain the list of monitored machines host_to_mac = powerwake.get_monitored_hosts(monitor.lower()) for ip, mac in host_to_mac.iteritems(): if host == ip: info("Updating information for [%s] in [%s] monitor" % (host, monitor)) mac = powerwake.get_mac_or_ip_from_arp(host) if not mac: error("Could not automatically determine MAC address for [%s]. Update cancelled." % host) host_to_mac[host] = mac powerwake.set_monitored_hosts(host_to_mac, monitor) return # add new # 1. If only IP is specified, try to automatically determine MAC if powerwake.is_ip(host) and macaddr is None: mac = powerwake.get_mac_or_ip_from_arp(host) if not mac: error("Could not automatically determine MAC Address for [%s]. Please specify MAC address." % host) # if mac given, look for ip host_to_mac[host] = mac # 2. If only MAC is specified, try to aumatically deftermine IP if powerwake.is_mac(host) and macaddr is None: ip = powerwake.get_mac_or_ip_from_arp(host) if not ip: error("Could not automatically determine IP address for [%s]. Please specify IP address." % host) host_to_mac[ip] = host # 3. If both MAC and IP are specified. if host and macaddr: info("Adding [%s - %s] to monitored hosts for [%s] monitor" % (host, macaddr, monitor)) host_to_mac[host] = macaddr powerwake.set_monitored_hosts(host_to_mac, monitor) def delete_host_from_monitor(powerwake, host, monitor): host_to_mac = powerwake.get_monitored_hosts(monitor.lower()) for ip, mac in host_to_mac.iteritems(): if host == ip or host == mac: info("Deleting %s from [%s] monitor" % (ip, monitor)) del host_to_mac[ip] powerwake.set_monitored_hosts(host_to_mac, monitor) break # List IP's to monitor def list_monitored_hosts(powerwake, monitor): hosts = powerwake.get_monitored_hosts(monitor.lower()) print " HOST - MAC" try: for ip, mac in hosts.iteritems(): print "%+20s - %-20s" % (ip, mac) except: error("Could not obtain monitored hosts") def list_available_monitors(powerwake): print " Listing available PowerWaked Monitors\n" for monitor in powerwake.MONITORS: print " [enabled] %+20s" % monitor['monitor'] if __name__ == '__main__': powerwake = powerwake.PowerWake() hasOptions = False # Option Parser usage = "usage: %prog \n\ \n\ %prog is a utility that allows to enable and disable available PowerNap\n\ actions.\n\ \n\ %prog --add [-c ] [-m ]\n\ %prog --del | [-m ]\n\ %prog --list [--monitor ]\n\ %prog --list-monitors" parser = OptionParser(usage) parser.add_option('-a', '--add', action='store', type='string', dest='add', help='Add host to Monitor', metavar='IP') parser.add_option('-d', '--del', action='store', type='string', dest='delete', help='Delete monitored host', metavar='IP') parser.add_option('-c', '--mac', action='store', type='string', dest='mac', help='specify MAC address', metavar='MAC', default=None) parser.add_option('-m', '--monitor', action='store', type='string', dest='monitor', help='specify monitor to add host', metavar='MONITOR', default='general') parser.add_option('-l', '--list', action='store_true', dest='list', help='List monitored hosts') parser.add_option('-o', '--list-monitors', action='store_true', dest='list_monitors', help='List enabled monitors') (opt, args) = parser.parse_args() if opt.list and opt.add: error("Options -l (--list) and -e (--enable) are mutually exclusive") sys.exit(1) if opt.list and opt.delete: error("Options -l (--list) and -d (--disable) are mutually exclusive") sys.exit(1) if opt.add and opt.delete: error("Options -e (--enable) and -d (--disable) are mutually exclusive") sys.exit(1) if opt.add: hasOptions = True add_host_to_monitor(powerwake, opt.add, opt.mac, opt.monitor) if opt.delete: hasOptions = True delete_host_from_monitor(powerwake, opt.delete, opt.monitor) if opt.list: hasOptions = True list_monitored_hosts(powerwake, opt.monitor) if opt.list_monitors: hasOptions = True list_available_monitors(powerwake) if not hasOptions: print parser.get_usage() powernap-2.18/sbin/powernap0000775000175000017500000000330212064361217016255 0ustar roaksoaxroaksoax#!/bin/sh -e # # powernap - have the system "take a nap"; this can be a user defined # program or script at /etc/powernap/action, or a best- # effort action among: # 1) suspend # 2) hibernate # 3) poweroff # # Copyright (C) 2009 Canonical Ltd. # # Authors: Dustin Kirkland # Andres Rodriguez # # 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, version 3 of the License. # # 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, see . PKG="powernap" ACTION_METHOD="$1" # Use the specified action, if configured # Otherwise, use the best available, supported sleep state best_effort() { if [ -x "/etc/$PKG/action" ]; then exec /etc/$PKG/action elif pm-is-supported --suspend; then exec /usr/sbin/pm-suspend elif pm-is-supported --hibernate; then exec /usr/sbin/pm-hibernate else exec /sbin/poweroff fi } # Raise the flag echo "$ACTION_METHOD" > /var/run/powernap.state case $ACTION_METHOD in 0) exec /usr/sbin/pm-powersave true exit ;; 1) exec /usr/sbin/pm-suspend exit ;; 2) exec /usr/sbin/pm-hibernate exit ;; 3) exec /sbin/poweroff exit ;; 4) best_effort exit ;; esac powernap-2.18/sbin/powerwaked0000775000175000017500000001451112064361217016576 0ustar roaksoaxroaksoax#!/usr/bin/python # # powerwaked - PowerNap Server Daemon # # Copyright (C) 2011 Canonical Ltd. # # Authors: Andres Rodriguez # # 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, version 3 of the License. # # 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, see . # Imports import commands import logging, logging.handlers import os import re import signal import sys import time import socket, traceback import struct from powerwake import powerwake powerwake.PKG = "powerwake" powerwake.DEBUG = int(3) powerwake.INTERVAL_SECONDS = int(1) # Initialize powerwake. This initialization loads the config file. try: powerwake = powerwake.PowerWake() pass except: print("Unable to initialize PowerNap Server") sys.exit(1) # Define globals global LOCK, CONFIG, MONITORS LOCK = "/var/run/%s.pid" % powerwake.PKG LOG = "/var/log/%s.log" % powerwake.PKG logging.basicConfig(filename=LOG, format='%(asctime)s %(levelname)-8s %(message)s', datefmt='%Y-%m-%d_%H:%M:%S', level=logging.DEBUG,) # Generic debug function def debug(level, msg): if level >= (logging.ERROR - 10*powerwake.DEBUG): logging.log(level, msg) # Generic error function def error(msg): debug(logging.ERROR, msg) sys.exit(1) # Lock function, using a pidfile in /var/run def establish_lock(): if os.path.exists(LOCK): f = open(LOCK,'r') pid = f.read() f.close() error("Another instance is running [%s]" % pid) else: try: f = open(LOCK,'w') except: error("Administrative privileges are required to run %s" % powerwake.PKG); f.write(str(os.getpid())) f.close() # Set signal handlers signal.signal(signal.SIGHUP, signal_handler) signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGQUIT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) signal.signal(signal.SIGIO, signal.SIG_IGN) signal.signal(signal.SIGUSR1, take_action_handler) # Clean up lock file on termination signals def signal_handler(signal, frame): if os.path.exists(LOCK): os.remove(LOCK) debug(logging.INFO, "Stopping %s" % powerwake.PKG) sys.exit(1) # Send a message to system users, that we're about to take an action, # and sleep for a grace period def warn_users(): timestamp = time.strftime("%Y-%m-%d_%H:%M:%S") msg1 = "[%s] PowerNap will take the following action in [%s] seconds: [%s]" % (timestamp, powerwake.GRACE_SECONDS, powerwake.ACTION) msg2 = "To cancel this operation, press any key in any terminal" debug(logging.WARNING, msg1) if powerwake.WARN: commands.getoutput("echo '%s\n%s' | wall" % (msg1, msg2)) # TODO: notify authorities about action taken def notify_authorities(): debug(logging.WARNING, "Taking action [%s]" % powerwake.ACTION) # Zero the counters and take the action def take_action(): notify_authorities() debug(logging.DEBUG, "Reseting counters prior to taking action") for monitor in MONITORS: monitor._absent_seconds = 0 os.system("%s %s" % (powerwake.ACTION, powerwake.ACTION_METHOD)) # Handler for asynchronous external signals def take_action_handler(signal, frame): take_action() def powerwaked_loop(): # Starting the Monitors for monitor in MONITORS: debug(logging.DEBUG, "Starting [%s] Monitoring" % monitor._type) for ip, mac in monitor._arp_cache.iteritems(): debug(logging.DEBUG, " Monitoring %s - %s" % (ip, mac)) monitor.start() users_warned = False while 1: debug(logging.DEBUG, "Sleeping [%d] seconds" % powerwake.INTERVAL_SECONDS) time.sleep(powerwake.INTERVAL_SECONDS) # Examine monitor activity, compute absent time of each monitored monitor process debug(logging.DEBUG, "Examining Monitors") absent_monitors = 0 for monitor in MONITORS: debug(logging.DEBUG, " Looking for [%s] %s" % (monitor._name, monitor._type)) if monitor.active(): monitor._absent_seconds = 0 debug(logging.DEBUG, " Activity found, reset absent time [%d]" % (monitor._absent_seconds)) else: # activity not found, increment absent time monitor._absent_seconds += powerwake.INTERVAL_SECONDS debug(logging.DEBUG, " Activity not found, increment absent time [%d]" % (monitor._absent_seconds)) # Determine if action needs to be taken if absent_monitors > 0 and absent_monitors == len(MONITORS): take_action() # "Forking a Daemon Process on Unix" from The Python Cookbook def daemonize (stdin="/dev/null", stdout="/var/log/%s.log" % powerwake.PKG, stderr="/var/log/%s.err" % powerwake.PKG): try: pid = os.fork() if pid > 0: sys.exit(0) except OSError, e: sys.stderr.write("fork #1 failed: (%d) %sn" % (e.errno, e.strerror)) sys.exit(1) os.chdir("/") os.setsid() try: pid = os.fork() if pid > 0: sys.exit(0) except OSError, e: sys.stderr.write("fork #2 failed: (%d) %sn" % (e.errno, e.strerror)) sys.exit(1) f = open(LOCK,'w') f.write(str(os.getpid())) f.close() for f in sys.stdout, sys.stderr: f.flush() si = file(stdin, 'r') so = file(stdout, 'a+') se = file(stderr, 'a+', 0) os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) # Main program if __name__ == '__main__': # Ensure that only one instance runs establish_lock() daemonize() try: # Run the main powernapd loop MONITORS = powerwake.get_monitors() debug(logging.INFO, "Starting %s" % powerwake.PKG) powerwaked_loop() finally: # Clean up the lock file if os.path.exists(LOCK): os.remove(LOCK) powernap-2.18/sbin/powerwake-now0000775000175000017500000000173712064361217017241 0ustar roaksoaxroaksoax#!/bin/sh -e # # powerwake-now - send powernapd the 'wakeup' signal # # Copyright (C) 2011 Canonical Ltd. # # Authors: Andres Rodriguez # # 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, version 3 of the License. # # 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, see . PKG="powernap" PIDFILE=/var/run/$PKG.pid if [ -r $PIDFILE ]; then echo "Sending $PKG the 'wakeup' signal" kill -USR2 $(cat $PIDFILE) exit $? else echo "$PKG does not appear to be running" exit 1 fi powernap-2.18/man/0000775000175000017500000000000012064361217014316 5ustar roaksoaxroaksoaxpowernap-2.18/man/powernap-now.80000664000175000017500000000207412064361217017046 0ustar roaksoaxroaksoax.TH powernap-now 8 "6 Feb 2010" powernap "powernap" .SH NAME powernap-now - send the powernapd daemon the 'powernap now' signal .SH DESCRIPTION When the \fBpowernapd\fP(8) runs, it is monitoring the system, and determining when it should take the specificied powernap action. If the administrator (or even other utilities or processes) could asynchronously determine that the system should 'powernap now', the \fBpowernap-now\fP(8) can be used to send the \fBpowernapd\fP(8) a signal, which will log the event and force a powernap immediately. .TP \fIhttp://launchpad.net/powernap\fP .PD .SH SEE ALSO \fBpowernapd\fP(8), \fBpowernap\fP(8) .SH AUTHOR This manpage and the utility was written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL. powernap-2.18/man/powernap-action.80000664000175000017500000000376512064361217017530 0ustar roaksoaxroaksoax.TH powernap-action 8 "19 Jan 2010" powernap "powernap-action" .SH NAME powernap-action \- enable or disable scripts to run when PowerNap's ACTION METHOD is PowerSave .SH SYNOPSIS .BI "powernap-action [\-e|\-\-enable ACTION] [\-d|\-\-disable ACTION ] [\-l|\-\-list]" .SH OPTIONS .TP .B \-e|\-\-enable ACTION Enable an ACTION script. .TP .B \-d|\-\-disable ACTION Disable an ACTION script. .TP .B \-l|\-\-list List available ACTIONS, with its current state (disabled or enabled). The ACTION scripts are available at \fI/etc/pm/power.d/\fP). .SH DESCRIPTION powernap-action will enable or disable any of the scripts available at \fI/etc/pm/power.d/\fP. These scripts are executed by \fBpm-powersave\fP when PowerNap ACTION METHOD is PowerSave. The ACTION_METHOD can be selected in \fI/etc/powernap/config\fP. Additionally, it can also list all the available scripts in \fI/etc/p/power.d/\fP. The list will show the available script, with is enabled or disabled status, and a description of what each scripts does. The scripts are compatible with \fBpm-utils\fP, to be able to be run with \fBpm-powersave\fP. If new scripts are added to \fI/etc/pm/power.d\fP and remain compatible to \fBpm-powersave\fp, \fBpowernap-action\fP will be able to perform the desired actions (enabled, disable, list). You may do one of: 1) \fBpowernap-action \-\-list\fP 2) \fBpowernap-action \-\-enable cpu_smp_sched\fP 3) \fBpowernap-action \-\-disable cpu_smp_sched\fP .TP \fIhttp://launchpad.net/powernap\fP .PD .SH FILES \fI/etc/powernap/config\fP .SH SEE ALSO \fBpowernapd\fP(8), \fBpm-powersave\fP(1) .SH AUTHOR This manpage and the utility was written by Andres Rodriguez for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL. powernap-2.18/man/powerwake.10000664000175000017500000000407412064361217016411 0ustar roaksoaxroaksoax.TH powerwake 1 "26 Jun 2009" powerwake "powerwake" .SH NAME powerwake \- smart utilty for remotely waking sleeping systems .SH SYNOPSIS .BI "powerwake [\-b|\-\-broadcast BROADCAST_IP] [\-m|\-\-method METHOD] TARGET_MAC|TARGET_IP|TARGET_HOST" .SH OPTIONS .TP .B \-b|\-\-broadcast BROADCAST_IP Optional parameter specifying the broadcast ip. If unspecified, the default is 255.255.255.255. .TP .B \-m|\-\-method METHOD Currently, 'wol' is the only supported method. .TP .B TARGET_MAC|TARGET_IP|TARGET_HOST The target system to powerwake may be identified by MAC address, or by an IP/hostname cached in (the current \fBarp\fP(8) table, \fI/etc/ethers\fP, \fI/var/cache/powerwake/ethers\fP). .SH DESCRIPTION The powerwake utility compliments the powernap(8) daemon. Administrators can run the powernap utility on remote hosts, allowing them to sleep when un-utilitized. To awake the remote system, use powerwake. Powerwake is designed to be "smart", and support multiple methods of waking remote hosts, such as wakeonlan, ipmi, and others. Currently, wakeonlan is the only implemented mechanism, though others are intended. Powerwake is also "smart" in that it can take MAC address, hostnames, or ip addresses. In the case of a hostname or ip address, powerwake will first load a dynamically maintained cache file \fI/var/cache/powerwake/ethers\fP, then a statically administered configuration file \fI/etc/ethers\fP, and finally use the arp table to determine the target MAC address. The cache will be updated accordingly. .TP \fIhttp://launchpad.net/powernap\fP .PD .SH FILES \fI/etc/ethers\fP, \fI/var/cache/powerwake/ethers\fP .SH SEE ALSO \fBarp\fP(8) .SH AUTHOR This manpage and the utility was written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL. powernap-2.18/man/powernap_calculator.10000664000175000017500000000315012064361217020443 0ustar roaksoaxroaksoax.TH powernap_calculator 1 "18 Aug 2009" powernap "powernap_calculator" .SH NAME powernap_calculator - estimate the expected power savings using powernap in a cloud environment .SH SYNOPSIS .BI "powernap_calculator [\-h|\-\-hosts NUM] [\-p|\-\-guests\-per\-host NUM] [\-g|\-\-guests NUM]" .SH OPTIONS .TP .B \-h, \-\-hosts NUM Number of physical host systems in your cloud. .TP .B \-p, \-\-guests\-per\-host NUM Number of virtual machine guests allowed to run on each physical host system (often, this is equal to the number of CPUs in the host system) .TP .B \-g, \-\-guests NUM Number of guest virtual machines running in the cloud at a given instant. .SH DESCRIPTION This utility will use statistical analysis to determine an expected value of power savings within a cloud environment using powernap. For more information about the statistical term 'expected value', please refer to: \fIhttp://en.wikipedia.org/wiki/Expected_value\fP. .TP \fIhttp://launchpad.net/powernap\fP .PD .SH EXAMPLE If your cloud consists of 8 hosts, each of which can run 4 guests, and you're currently running 16 guests, you can see your power savings expected value with: powernap_calculator \-h 8 \-p 4 \-g 16 .SH AUTHOR This manpage and the utility was written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL. powernap-2.18/man/powernapd.80000664000175000017500000000527612064361217016420 0ustar roaksoaxroaksoax.TH powernapd 8 "9 Jun 2009" powernap "powernapd" .SH NAME powernapd \- configurable daemon that will run at a specified INTERVAL_SECONDS, executing powernap when all of a list of MONITORS are missing or inactive for a contiguous ABSENT_SECONDS. .SH DESCRIPTION powernapd will run \fBpowernap\fP(8) when none of a set of MONITORS have executed for some number of ABSENT_SECONDS. powernapd will check for activity on each enabled monitor every INTERVAL_SECONDS. Note that MONITORS taking less than INTERVAL_SECONDS to execute may be overlooked by powernapd. Choose your INTERVAL_SECONDS value accordingly. These parameters are configured in \fI/etc/powernap/config\fP. It acts as a sort of "screensaver" for servers, watching the process table for activity, rather than the keyboard or mouse. For instance, PowerNap can automatically "pm-suspend" a system if no instance of "kvm" runs for some contiguous block of "300" seconds, checking the process table every "1" second. The available MONITORS are: .TP .B [ConsoleMonitor] Tracks activity in any console (tty), as well as activity of any PS2 connected mouse or keyboard. Monitor enabled by default. .TP .B [ProcessMonitor] Tracks activity by searching for a process regex in the Process Table. .TP .B [InputMonitor] Tracks Input activity from \fI/dev/input\fP. It usually tracks keyboard and mice activity connected through USB. .TP .B [LoadMonitor] Tracks system load activity given a load threshold. Monitor enabled by default, with a threshold matching the number of processors in the system. .TP .B [WoLMonitor] Tracks WoL data packets received in any of the network interfaces (eth's). Monitor enabled by default to listen in ports 7 and 9. .TP .B [TCPMonitor] Tracks TCP activity by checking any ESTABLISHED connection in any port, such as ssh, httpd, etc. .TP .B [UDPMonitor] Tracks UDP activity by binding any specific port. .TP .B [IOMonitor] Tracks Process I/O activity for a given process name, or regex. .TP For more information about the MONITORS, refer to \fI/etc/powernap/config\fP. .PD .TP \fIhttp://launchpad.net/powernap\fP .PD .SH FILES \fI/etc/powernap/action\fP, \fI/etc/powernap/config\fP, \fI/var/run/powernap.pid\fP, \fI/var/log/powernap.log\fP, \fI/var/log/powernap.err\fP .SH SEE ALSO \fBpgrep\fP(1), \fBpowernap\fP(8)) .SH AUTHOR This manpage and the utility was written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL. powernap-2.18/man/powerwake-now.80000664000175000017500000000216312064361217017216 0ustar roaksoaxroaksoax.TH powerwake-now 8 "16 Feb 2011" powernap "powernap" .SH NAME powerwake-now - send the powernapd daemon the 'powerwake now' signal .SH DESCRIPTION When the \fBpowernapd\fP(8) runs, it is monitoring the system, and determining when it should take the specificied powernap action. If the administrator (or even other utilities or processes) could asynchronously determine that the system should 'powerwake now' from the powersave mode, the \fBpowerwake-now\fP(8) can be used to send the \fBpowernapd\fP(8) a signal, which will log the event and force a wake-up from the powersave mode immediately. .TP \fIhttp://launchpad.net/powernap\fP .PD .SH SEE ALSO \fBpowernapd\fP(8), \fBpowernap\fP(8) .SH AUTHOR This manpage and the utility was written by Andres Rodriguez for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL. powernap-2.18/man/powernap.80000664000175000017500000000440712064361217016247 0ustar roaksoaxroaksoax.TH powernap 8 "2 Jul 2009" powernap "powernap" .SH NAME powernap - have the system "take a power nap"; this can be a user defined ACTION_METHOD in \fI/etc/powernap/config\fP among [best-effort, suspend, hibernate, poweroff, powersave] .SH DESCRIPTION powernap will run when \fBpowernapd\fP(8) has determined that an action needs to be taken according to its configured parameters. The action to be taken, among [best-effort, suspend, hibernate, poweroff], is determined in \fI/etc/powernap/config\fP. By default, the action will be \fBbest-effort\fP. When the ACTION_METHOD is \fBbest-effort\fP, and if the file \fI/etc/powernap/action\fP is executable, then the powernap binary will run it when called. Otherwise, powernap will run one of: * pm-suspend * pm-hibernate * poweroff depending on your hardware's capabilities, as determined by \fBpm-is-supported\fP(1). You may do one of: 1) Write your own custom at \fI/etc/powernap/action\fP and make it executable 2) Replace \fI/etc/powernap/action\fP with an executable script or binary 3) Symlink \fI/etc/powernap/action\fP to some other executable script or binary When ACTION_METHOD is \fBpowersave\fP, then powernap binary will execute \fBpm-suspend\fP. When ACTION_METHOD is \fBpowersave\fP, then powernap binary will execute \fBpm-hibernate\fP. When ACTION_METHOD is \fBpowersave\fP, then powernap binary will execute \fBpoweroff\fP. When ACTION_METHOD is \fBpowersave\fP, then powernap binary will execute \fBpm-powersave\fP and pass an argument (true) to execute all the available scripts at \fI/usr/lib/pm-utils/power.d/\fP and \fI/etc/pm/power.d/\fP. The latter will contain scripts shipped with powernap. .TP \fIhttp://launchpad.net/powernap\fP .PD .SH FILES \fI/etc/powernap/action\fP, \fI/proc/acpi/sleep\fP .SH SEE ALSO \fBpowernapd\fP(8), \fBpm-is-supported\fP(1), \fBethtool\fP(8) .SH AUTHOR This manpage and the utility was written by Dustin Kirkland for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL. powernap-2.18/powerwake/0000775000175000017500000000000012064361217015547 5ustar roaksoaxroaksoaxpowernap-2.18/powerwake/monitors/0000775000175000017500000000000012064361217017421 5ustar roaksoaxroaksoaxpowernap-2.18/powerwake/monitors/ARPMonitor.py0000664000175000017500000000446612064361217021777 0ustar roaksoaxroaksoax# # powernapd plugin - ARP Monitor for auto-wakeup of client machines # # Copyright (C) 2011 Canonical Ltd. # # Authors: Andres Rodriguez # Jim Heck # # 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, version 3 of the License. # # 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, see . import os, threading from logging import error, debug, info, warn from scapy.all import * #from scapy.all import sniff, ARP, Ether, IP, UDP, Raw, sendp # Converts the MAC to some weird format def mac_to_string(mac): return str(Ether(dst=mac))[:6] # Create a WoL magic packet def make_magic(sleeper_mac_str): return Ether(dst='ff:ff:ff:ff:ff:ff')/IP(dst='255.255.255.255')/UDP(dport=7)/Raw(load='\xff\xff\xff\xff\xff\xff' + sleeper_mac_str * 16) class ARPMonitor(threading.Thread): # Initialise def __init__(self, config): threading.Thread.__init__(self) self._type = config['monitor'] self._name = "ARP Monitor" self._arp_cache = config['cache'] self._absent_seconds = 0 self._running = False # Check for PIDs def active(self): return False # Start thread def start(self): self._running = True threading.Thread.start(self) # Stop thread def stop(self): self._running = False def run(self): while self._running: sniff(prn=self.arp_wake_sleeper_callback, filter="arp", store=0) def arp_wake_sleeper_callback(self, pkt): # evaluates if received ARP packet with dest ip (pkt[ARP].pdst) is in cache if ARP in pkt and pkt[ARP].op == 1 and pkt[ARP].pdst in self._arp_cache: # If found in arp_cache, then try to wake up by sending a WoL. magic_pkt = make_magic(mac_to_string(self._arp_cache[pkt[ARP].pdst])) sendp(magic_pkt) powernap-2.18/powerwake/monitors/__init__.py0000664000175000017500000000000012064361217021520 0ustar roaksoaxroaksoaxpowernap-2.18/powerwake/powerwake.py0000664000175000017500000001453312064361217020133 0ustar roaksoaxroaksoax#!/usr/bin/python # # powerwake.py - handles powerwaked config and initializes Monitors. # # Copyright (C) 2011 Canonical Ltd. # # Authors: Andres Rodriguez # # 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, version 3 of the License. # # 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, see . import ConfigParser, sys, re, os #from monitors import ARPMonitor class PowerWake: def __init__(self): self.PKG = "powerwake" self.CONFIG = "/etc/powernap/powerwaked.conf" self.ACTION = "/usr/bin/powerwake" self.INTERVAL_SECONDS = int(1) self.DEBUG = int(0) self.MONITORS = [] # Load default config file (/etc/powernap/config) self.load_config_file() def load_config_file(self): cfg = ConfigParser.ConfigParser() cfg.read(self.CONFIG) try: # Load items in DEFAULT section defaults = cfg.items(self.PKG) for items in defaults: self.set_default_values(items[0], items[1]) monitors_config = cfg.sections() for monitor in monitors_config: for items in cfg.items(monitor): self.load_monitors_config(monitor, items) except: pass def set_default_values(self, var, value): if var == "interval_seconds": self.INTERVAL_SECONDS = eval(value) if var == "debug": self.DEBUG = eval(value) if var == "action": self.ACTION = eval(value) if var == "warn": if value == "y" or value == "yes": self.WARN = True def load_monitors_config(self, monitor, items): if monitor == "ARPMonitor" and (items[1] == "y" or items[1] == "yes"): self.MONITORS.append({"monitor":monitor, "cache":self.get_monitored_hosts(monitor.lower())}) def get_monitors(self): from monitors import ARPMonitor monitor = [] for config in self.MONITORS: if config["monitor"] == "ARPMonitor": p = ARPMonitor.ARPMonitor(config) monitor.append(p) return monitor def get_monitored_hosts(self, monitor): host_to_mac = {} for file in ["/etc/powernap/powerwaked.%s.ethers" % monitor]: if os.path.exists(file): f = open(file, 'r') for i in f.readlines(): try: (m, h) = i.split() host_to_mac[h] = m except: pass f.close() return host_to_mac def set_monitored_hosts(self, host_to_mac, monitor): path = ["/etc/powernap/powerwaked.%s.ethers" % monitor] for file in path: if not os.path.exists(file): f = open(file, 'a') f.close() for file in ["/etc/powernap/powerwaked.%s.ethers" % monitor]: if os.access(file, os.W_OK): f = open(file, 'w') for h in host_to_mac: if self.is_mac(host_to_mac[h]): f.write("%s %s\n" % (host_to_mac[h], h)) f.close() def get_mac_or_ip_from_arp(self, host): mac_or_ip = None for i in os.popen("/usr/sbin/arp -n"): m = i.split()[2] h = i.split()[0] if self.is_mac(host) and host == m and self.is_ip(h): mac_or_ip = h break if self.is_ip(host) and host == h and self.is_mac(m): mac_or_ip = m break #if not mac_or_ip: # raise BaseException("Error") return mac_or_ip def is_ip(self, ip): r1 = re.compile('^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$') if r1.match(ip): return True else: return False def is_mac(self, mac): r1 = re.compile('^[0-9a-fA-F]{12}$') r2 = re.compile('^[0-9a-fA-F]{2}.[0-9a-fA-F]{2}.[0-9a-fA-F]{2}.[0-9a-fA-F]{2}.[0-9a-fA-F]{2}.[0-9a-fA-F]{2}$') if r1.match(mac) or r2.match(mac): return 1 else: return 0 #### --------------------------------- from powerwake --------------------------------#### # Source the cached, known arp entries def get_arp_cache(self): host_to_mac = {} #for file in ["/var/cache/%s/ethers" % self.PKG, "/etc/ethers", "%s/.cache/ethers" % HOME]: for file in ["/var/cache/%s/ethers" % self.PKG, "/etc/ethers"]: if os.path.exists(file): f = open(file, 'r') for i in f.readlines(): try: (m, h) = i.split() host_to_mac[h] = m except: pass f.close() return host_to_mac # Source the current, working arp table def get_arp_current(self, host_to_mac): # Load hostnames for i in os.popen("/usr/sbin/arp"): m = i.split()[2] h = i.split()[0] if is_mac(m): host_to_mac[h] = m # Load ip addresses for i in os.popen("/usr/sbin/arp -n"): m = i.split()[2] h = i.split()[0] if is_mac(m): host_to_mac[h] = m return host_to_mac def write_arp_cache(self, host_to_mac): if not os.access("%s/.cache/" % HOME, os.W_OK): return if not os.path.exists("%s/.cache/" % HOME): os.makedirs("%s/.cache/" % HOME) f = open("%s/.cache/ethers" % HOME, 'a') f.close() for file in ["/var/cache/%s/ethers" % PKG, "%s/.cache/ethers" % HOME]: if os.access(file, os.W_OK): f = open(file, 'w') for h in host_to_mac: if self.is_mac(host_to_mac[h]): f.write("%s %s\n" % (host_to_mac[h], h)) f.close() powernap-2.18/powerwake/__init__.py0000664000175000017500000000000012064361217017646 0ustar roaksoaxroaksoaxpowernap-2.18/powerwaked.conf0000664000175000017500000000010512064361217016556 0ustar roaksoaxroaksoax[powerwake] INTERVAL_SECONDS = 1 DEBUG = 3 [ARPMonitor] enable = y powernap-2.18/powerwake_completion0000664000175000017500000000177512064361217017735 0ustar roaksoaxroaksoax# powerwake(1) completion have powerwake && _powerwake() { local cur prev options files targets COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" options="-b --broadcast -m --method" files="/etc/ethers /var/cache/powerwake/ethers $HOME/.cache/ethers" targets="$( cat ${files} 2>/dev/null | awk '{print $2}' )" case "${prev}" in -@(b|-broadcast)) COMPREPLY=( $( compgen -W "$( LANG=C ifconfig 2>/dev/null | \ awk '/Bcast:/ {print $3}' | awk -F ':' '{print $2}' )" \ -- ${cur} ) ) return 0 ;; -@(m|-method)) COMPREPLY=( $( compgen -W "wol" -- ${cur} ) ) return 0 ;; *) ;; esac if [[ ${cur} == -* ]] ; then COMPREPLY=( $( compgen -W "${options}" -- ${cur} ) ) return 0 else COMPREPLY=( $( compgen -W "${targets}" -- ${cur} ) ); return 0 fi } complete -F _powerwake powerwake