'''
daemon.py - daemon starter service for sagator

(c) 2005-2016 Jan ONDREJ (SAL) <ondrejj(at)salstar.sk>

 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.

'''

from aglib import *

__all__=['chroot_execvp','chroot_execvpe','scand']

class chroot_execvp(service):
  '''
  Execute an external command (or start an daemon).
  
  This service can be used to start external daemons used by sagator.
  
  Usage: chroot_execvp('daemon_name',args=[],pid_file='')
  
  Where: daemon_name is a string, which defines command name
         args are strings, which defines command line arguments
         pid_file is an string to filename with PID of started daemon
         pgrp_file is an string to a process group filename
  
  Example: chroot_execvp('/usr/sbin/clamd','-c','/etc/clamav.conf')
  
  New in version 0.7.0.
  '''
  name='chroot_execvp()'
  def __init__(self,command,args=[],pid_file='',pgrp_file=''):
      self.CMD=[command]+list(args)
      self.ENV={}
      self.PID_FILE=pid_file
      self.PGRP_FILE=pgrp_file
  def stop(self):
      if self.PID_FILE:
        try:
          pid=int(open(safe.ROOT_PATH+self.PID_FILE).read())
          debug.echo(1,'%s: Killing %s pid=%d' % (self.name,self.PID_FILE,pid))
          os.kill(pid,signal.SIGTERM)
        except IOError:
          debug.echo(1,"%s: Can't open file %s" % (self.name,self.PID_FILE))
        except OSError as err:
          (ec,es) = err.args
          debug.echo(0,"%s: kill: %s" % (self.name,es))
      if self.PGRP_FILE:
        try:
          pgrp=int(open(safe.ROOT_PATH+self.PGRP_FILE).read())
          debug.echo(1,'%s: Killing %s pgrp=%d' % (self.name,self.PGRP_FILE,pgrp))
          os.killpg(pgrp,signal.SIGTERM)
        except AttributeError:
          # python 2.2 or later? Try to use kill command.
          os.system('/bin/kill -TERM -- -%d' % pgrp)
        except IOError:
          debug.echo(1,"%s: Can't open file %s" % (self.name,self.PGRP_FILE))
        except OSError as err:
          (ec,es) = err.args
          debug.echo(0,"%s: killpg: %s" % (self.name,es))
  def start(self):
      self.pid=os.fork()
      if self.pid==0:
        debug.echo(1,'%s: %s' % (self.name,self.CMD))
        try:
          os.chroot(safe.ROOT_PATH)
          if self.ENV:
            os.execvpe(self.CMD[0],self.CMD,self.ENV)
          else:
            os.execvp(self.CMD[0],self.CMD)
        except OSError as err:
          (ec,es) = err.args
          debug.echo(0,"%s: WARNING: Can't start process in chroot: %s" \
                     % (self.name,es))
      return [self.pid]

class chroot_execvpe(chroot_execvp):
  '''
  Execute an external command (or start an daemon) and update variables.
  
  This service can be used to start external daemons used by sagator.
  You also can set environment varibles.
  
  Usage: chroot_execvpe('daemon_name',args=[],env={})
  
  Where: daemon_name is a string, which defines command name
         args are strings, which defines command line arguments
         env is an dictionary of environment variables
         pid_file is an string to filename with PID of started daemon
         pgrp_file is an string to a process group filename
  
  Example: chroot_execvpe('/usr/sbin/clamd',['-c','/etc/clamav.conf'],
                          {'LANG': 'C'})
  
  New in version 0.7.0.
  '''
  name='chroot_execvpe()'
  def __init__(self,command,args=[],env={},pid_file='',pgrp_file=''):
      self.CMD=[command]+list(args)
      self.ENV=env
      self.PID_FILE=pid_file
      self.PGRP_FILE=pgrp_file

class scand(chroot_execvpe):
  '''
  Scanner daemon with a preload library ability.
  
  This service can be used to scan for viruses with an library, which
  can be "preloaded" as LD_PRELOAD library.
  
  Usage: scand(scanner,ld_preload='',
               sock='/tmp/scand.sock',
               pid_file='/var/run/scand.pid',
               as_root=False)
  
  Where: scanner is a scand scanner
         ld_preload is an library name, which can be preloaded with
           LD_PRELOAD parameter. By default by library will be preloaded.
         sock is path to communicate with scanner
         pid_file is a path to store daemon's pid file. This will be loaded
           at exit and this process will be killed.
         as_root is an boolean. Set it to True if you want to run scanners
           in scand as root.
  
  Example: scand(nod2pac(),ld_preload='/usr/lib/libnod32pac.so')
       or: scand(usrquota('mydomain.sk'),as_root=True)
  
  New in version 0.8.0.
  '''
  name='scand()'
  def __init__(self,scanner,ld_preload='',
               sock='/tmp/scand.sock',
               pid_file='/var/run/scand.pid',
               as_root=False):
      self.SCANNER=scanner
      self.CMD=[
        os.path.join(
          os.path.dirname(os.path.realpath(sys.argv[0])),
          'scand.py'
        )
      ]
      if as_root:
        self.CMD.append('--as-root')
      if ld_preload:
        self.ENV={'LD_PRELOAD': ld_preload}
      else:
        self.ENV={}
      self.SOCK=sock
      self.PID_FILE=pid_file
  def stop(self):
      try:
        pid=int(open(self.PID_FILE).read())
        debug.echo(1,'%s: Killing %s pid=%d' % (self.name,self.PID_FILE,pid))
        os.kill(pid,signal.SIGTERM)
      except IOError:
        debug.echo(1,"%s: Can't open file %s" % (self.name,self.PID_FILE))
      except OSError as err:
        (ec,es) = err.args
        debug.echo(0,"%s: kill: %s" % (self.name,es))
      except ValueError:
        pass # no process running
  def start(self):
      self.pid=os.fork()
      if self.pid==0:
        debug.echo(1,'%s: %s %s' % (self.name,self.CMD,self.ENV))
        try:
          os.execvpe(self.CMD[0],self.CMD,self.ENV)
        except OSError as err:
          (ec,es) = err.args
          debug.echo(0,"%s: WARNING: Can't start process: %s" \
                     % (self.name,es))
      os.wait() # wait to daemonize scand
      return [self.pid]
