#!/usr/bin/python3
# -*- coding: utf-8; -*-
#
# (c) 2008-2010 Mandriva, http://www.mandriva.com/
#
# $Id$
#
# This file is part of Pulse 2, http://pulse2.mandriva.org
#
# Pulse 2 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.
#
# Pulse 2 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 Pulse 2.  If not, see <http://www.gnu.org/licenses/>.

"""
Pulse 2 Package Server daemon.
"""

import os
import os.path
import sys
import getopt
import logging
import logging.config
import twisted
import twisted.copyright

from mmc.site import mmcconfdir
from pulse2.package_server import ThreadLauncher, init_logger_debug, getVersion, getRevision
from pulse2.package_server.config import P2PServerCP

def running(inifile, daemonize, noconsoledebug = True):
    config = P2PServerCP()
    config.pre_setup(inifile)

    # Try to create the default log directory
    if not os.path.exists(config.logdir):
        try:
            os.mkdir(config.logdir)
        except:
            # Maybe we are not root, so it may not be a problem if the mkdir
            # failed
            pass

    logging.config.fileConfig(inifile)
    logger = logging.getLogger()
    logger.debug("Logger loaded")
    logger.info("Pulse 2 Package Server %s starting..." % getVersion())
    logger.info("Pulse 2 Package server build '%s'" % str(getRevision()))
    logger.info("Using Python %s" % sys.version.split("\n")[0])
    logger.info("Using Python Twisted %s" % twisted.copyright.version)
    init_logger_debug()

    config.setup(inifile)

    # Set umask and effective UID and GID values
    os.umask(config.umask)
    os.setegid(config.daemon_group)
    os.seteuid(config.daemon_user)
    logger.debug("Running as euid = %d, egid = %d" % (os.geteuid(), os.getegid()))

    if config.real_package_deletion:
        logger.warning("Real package deletion is activated")

    # When starting, we log to stderr too if we don't become a daemon
    # As there is a lot of log possible during the init of pserver, we no
    # longer log to stderr if we daemonize later
    if not daemonize:
        if noconsoledebug:
            hdlr2 = logging.StreamHandler()
            logger.addHandler(hdlr2)
            logging.getLogger('imaging').addHandler(hdlr2)

    try:
        ThreadLauncher().initialize(config)
    except Exception, e:
        logger.exception(e)
        raise
    twisted.internet.reactor.addSystemEventTrigger('before', 'shutdown', cleanUp, config)

    # Become a daemon
    if daemonize:
        daemon(config)
        # No more log to stderr
        # logger.removeHandler(hdlr2)

    ThreadLauncher().runThreads()
    twisted.internet.reactor.run()
    return 0

def cleanUp(config):
    logger = logging.getLogger()
    logger.info('Pulse 2 Package Server shutting down, cleaning up...')

    # Unlink pidfile if it exists
    if os.path.isfile(config.pidfile):
        os.seteuid(0)
        os.setegid(0)
        os.unlink(config.pidfile)

def daemon(config):
    """
    daemonize pulse2-package-server

    @param pidfile: path to pid file
    @type pidfile: str
    """
    pidfile = config.pidfile

    # Test if mmcagent has been already launched in daemon mode
    if os.path.isfile(pidfile):
        print pidfile+" pid already exist. Maybe pulse2-package-server is already running\n"
        print "use /etc/init.d script to stop and relaunch it"
        sys.exit(0)

    # do the UNIX double-fork magic, see Stevens' "Advanced
    # Programming in the UNIX Environment" for details (ISBN 0201563177)
    try:
        pid = os.fork()
        if pid > 0:
            # exit first parent
            sys.exit(0)
    except OSError, e:
        print >>sys.stderr, "fork #1 failed: %d (%s)" % (e.errno, e.strerror)
        sys.exit(1)

    # decouple from parent environment
    os.close(sys.stdin.fileno())
    os.close(sys.stdout.fileno())
    os.close(sys.stderr.fileno())
    os.chdir("/")
    os.setsid()

    # do second fork
    try:
        pid = os.fork()
        if pid > 0:
            # exit from second parent, print eventual PID before
            print "Daemon PID %d" % pid
            os.seteuid(0)
            os.setegid(0)
            os.system("echo " + str(pid) + " > " + pidfile)
            sys.exit(0)
    except OSError, e:
        print >>sys.stderr, "fork #2 failed: %d (%s)" % (e.errno, e.strerror)
        sys.exit(1)

if __name__ == "__main__":
    inifile = mmcconfdir + "/pulse2/package-server/package-server.ini"
    try:
        opts, suivarg = getopt.getopt(sys.argv[1:], "f:ds")
    except getopt.GetoptError:
        sys.exit(2)
    daemonize = True
    debugtoconsole = True
    for option, argument in opts:
        if option == "-f":
            inifile = argument
        elif option == "-d":
            daemonize = False
        elif option == "-s":
            daemonize = False
            debugtoconsole = False

    if not os.path.exists(inifile):
        print "File '%s' does not exist." % inifile
        sys.exit(3)

    # Start the daemon main loop
    sys.exit(running(inifile, daemonize, debugtoconsole))
