#!/bin/python # -*- coding: utf-8 -*- ############################################################################ # Copyright (C) 2008 by Alex Brandt # # # # This program is free software; you can redistribute it and#or modify # # it under the terms of the GNU General Public License as published by # # the Free Software Foundation; either version 2 of the License, or # # (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program; if not, write to the # # Free Software Foundation, Inc., # # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################ import dbus import os import sys import optparse import signal import resource import re import time import logging class DbusDaemon: def __init__(self): self._parseOptions() self._log_level = self._LEVELS[self._options.level] self._WORKDIR = os.environ['HOME'] + "/." + sys.argv[0] if (not os.path.isdir(self._WORKDIR)): os.mkdir(self._WORKDIR, 0755) self._PID_FILE = self._WORKDIR + "/" + sys.argv[0] + ".pid" logging.basicConfig( filename=self._WORKDIR + "/" + sys.argv[0] + ".log", level=self._log_level) if self._options.kill: self._killRunningDaemon() self._dbusSession = dbus.SessionBus() def _removePidFile(self): logging.info("{_removePidFile} print: self._PID_FILE -> " + self._PID_FILE) os.unlink(self._PID_FILE) def _killRunningDaemon(self): logging.info("{_killRunningDaemon} print: Shutting down.") if (os.path.isfile(self._PID_FILE)): pid = open(self._PID_FILE, 'r').readlines() if len(pid) > 1: raise RuntimeError("Incorrect format of pid file.") self._removePidFile() try: os.kill(int(pid[0]), signal.SIGTERM) except OSError, e: raise OSError, "%s [%d]" % (e.strerror, e.errno) logging.shutdown() os._exit(os.EX_OK) def _keepKScreenSaverFromStarting(self): logging.debug("{_keepKScreenSaverFromStarting} print: Beginning execution of self._keepKScreenSaverFromStarting().") kscreensaver = self._dbusSession.get_object("org.freedesktop.ScreenSaver", "/ScreenSaver") logging.debug("{_keepKScreenSaverFromStarting} print: Got dbus object for the screensaver.") kscreensaver.SimulateUserActivity(dbus_interface="org.freedesktop.ScreenSaver") logging.debug("{_keepKScreenSaverFromStarting} print: Called kscreensaver.SimulateUserActivity().") def _parseOptions(self): description_list = [ "%prog is a daemonized utility that periodically simulates user ", "activity to keep KScreenSaver from activating by taking ", "advantage of the DBUS interface provided." ] parser = optparse.OptionParser(usage="usage: %prog [options]", version="%prog 1.0", description="".join(description_list)) time_list = [ "The time (with an appropriate unit notation) between activity ", "markers to KScreenSaver. The units are denoted in the usual ", "fashion:\n", "\ts -> seconds\n", "\tm -> minutes\n", "\th -> hours\n", "\n", "These can be specified together like: 1d4h3s or individually ", "to multiple -t (--time) options. The numbers may be floating ", "point numbers (2.5)." ] parser.add_option('--time', '-t', type="string", action="append", help="".join(time_list)) kill_list = [ "If this option is passed it will kill the currently running ", "daemon." ] parser.add_option('--kill', '-k', action="store_true", default=False, help="".join(kill_list)) self._LEVELS = { 'debug' : logging.DEBUG, 'info' : logging.INFO, 'warning' : logging.WARNING, 'error' : logging.ERROR, 'critical' : logging.CRITICAL } log_level_list = [ "Specifies the level of logging to perform to the log file. " "The levels can be any of the following: ", "".join(self._LEVELS.keys()), ". The lowest level is debug and a low level will include all ", "higher levels in the logger output." ] parser.add_option('--level', '-l', type="choice", choices=self._LEVELS.keys(), default="warning", help="".join(log_level_list)) self._options, self._arguments = parser.parse_args() def _getTimeInSeconds(self): logging.debug("{_getTimeInSeconds} print: Starting execution of self._getTimeInSeconds().") hour_expression = "(?P\d+?\.?\d*?)h" minute_expression = "(?P\d+?\.?\d*?)m" seconds_expression = "(?P\d+?\.?\d*?)s" default_expression = "(?P\d+?\.?\d*?$)" expression_string = "^((" + hour_expression + "|" + minute_expression + "|" + seconds_expression + ")+?$|" + default_expression + ")" logging.debug("{_getTimeInSeconds} print: expression_string -> " + expression_string) try: expression = re.compile(expression_string) except: logging.critical("{_getTimeInSeconds} print: ", exc_info=True) self._removePidFile() sys._exit(os.EX_SOFTWARE) logging.debug("{_getTimeInSeconds} print: self._options.time -> " + "".join(self._options.time)) try: match = expression.match("".join(self._options.time)) except: logging.critical("{_getTimeInSeconds} print: ", exc_info=True) self._removePidFile() sys._exit(os.EX_SOFTWARE) logging.debug("{_getTimeInSeconds} print: bool(match) -> " + str(bool(match))) logging.debug("{_getTimeInSeconds} print: len(match.groupdict()) -> " + str(len(match.groupdict()))) if (match): ret = 0.0 for i in range(len(match.groupdict())): try: key = match.groupdict().keys()[i] atom = match.groupdict()[key] logging.debug("{_getTimeInSeconds} print: key => atom -> " + str(key) + " => " + str(atom)) if atom == None: continue if key == "hours": ret += float(atom)*3600 elif key == "minutes": ret += float(atom)*60 else: ret += float(atom) except: self._exceptionHandler("_getTimeInSeconds") logging.debug("{_getTimeInSeconds} print: ret -> " + str(ret)) return ret else: error_list = [ "Could not determine the number of seconds from the --time ", "option." ] raise RuntimeError, "".join(error_list) def Run(self): logging.debug("{Run} print: Beginning execution of self.Run().") while True: logging.debug("{Run} print: Inside the infinite loop.") self._keepKScreenSaverFromStarting() logging.debug("{Run} print: Just returned from self._keepKScreenSaverFromStarting().") try: logging.debug("{Run} print: self._getTimeInSeconds() -> " + str(self._getTimeInSeconds())) except: self._exceptionHandler("Run") time.sleep(self._getTimeInSeconds()) logging.debug("{Run} print: Just got back from the time.sleep().") def _exceptionHandler(self, name): logging.critical("{" + name + "} print: ", exc_info=True) self._removePidFile() sys._exit(os.EX_SOFTWARE) def Daemonize(self): self._UMASK = 0 self._MAXFD = 1024 self._checkForAnotherDaemon() if (hasattr(os, "devnull")): self._REDIRECT_TO = os.devnull else: self._REDIRECT_TO = "/dev/null" self._daemonize() logging.info("{Daemonize} print: Starting up.") logging.debug("{Daemonize} print: Returned from self._daemonize().") self._writePidFile() logging.debug("{Deamonize} print: Returned from self._writePidFile().") self.Run() def _writePidFile(self): pid_file = open(self._PID_FILE, 'w') pid_file.write(str(os.getpid())) def _checkForAnotherDaemon(self): if (os.path.isfile(self._PID_FILE)): pid = open(self._PID_FILE, 'r').readlines() if len(pid) > 1: raise RuntimeError("Incorrect format of pid file.") raise RuntimeError, "%s [%d]" % ("Daemon already running", int(pid[0])) logging.shutdown() sys.exit(os.EX_CONFIG) def _daemonize(self): try: pid = os.fork() except OSError, e: raise OSError, "%s [%d]" % (e.strerror, e.errno) if (pid == 0): os.setsid() try: pid = os.fork() except OSError, e: raise OSError, "%s [%d]" % (e.strerror, e.errno) if (pid == 0): os.chdir(self._WORKDIR) os.umask(self._UMASK) else: logging.shutdown() os._exit(os.EX_OK) else: logging.shutdown() os._exit(os.EX_OK) self._maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1] if (self._maxfd == resource.RLIM_INFINITY): self._maxfd = self._MAXFD logging.debug("{_daemonize} print: PID -> " + str(os.getpid())) logging.debug("{_daemonize} print: self._maxfd -> " + str(self._maxfd)) for fd in range(0, 3): logging.debug("{_daemonize} print: Inside loop that closes files.") try: os.close(fd) except OSError, e: logging.warning(exc_info=True) logging.debug("{_daemonize} print: Finished closing files.") os.open(self._REDIRECT_TO, os.O_RDWR) os.dup2(0, 1) os.dup2(0, 2) logging.debug("{_deamonize} print: Returning from self._daemonize().") def main(): app = DbusDaemon() app.Daemonize() if __name__ == "__main__": main()