#!/usr/bin/python3
#
# Univention Management Console
#  handles UMC requests for a specified UMC module
#
# SPDX-FileCopyrightText: 2006-2025 Univention GmbH
# SPDX-License-Identifier: AGPL-3.0-only

import locale
import logging
import os
import os.path
import sys
from argparse import ArgumentParser

# don't import univention.management.console.modules here as the locale is not yet set!
import univention.logging
from univention.lib.i18n import Locale, Translation
from univention.management.console.config import MODULE_DEBUG_LEVEL, MODULE_INACTIVITY_TIMER, ucr
from univention.management.console.log import MODULE, RequestFilter, add_filter, log_init


if __name__ == '__main__':
    if os.getuid() != 0:
        sys.stderr.write('%s must be started as root\n' % os.path.basename(sys.argv[0]))
        sys.exit(1)

    parser = ArgumentParser()
    parser.add_argument('-s', '--socket', help='defines the socket to bind to')
    parser.add_argument('-l', '--language', default='C', help='defines the language to use')
    parser.add_argument('-m', '--module', help='set the UMC daemon module to load')

    parser.add_argument('-d', '--debug', type=int, default=MODULE_DEBUG_LEVEL, help='if given then debugging is activated and set to the specified level [default: %(default)s]')
    parser.add_argument('-L', '--log-file', dest='logfile', default='management-console-module-%(module)s', help='specifies an alternative log file [default: %(default)s.log]')
    parser.add_argument('-f', '--foreground', action='store_true', default=False, help='start in foreground, do not daemonize the process')

    options = parser.parse_args()

    os.umask(0o077)
    os.chdir("/")
    if not options.foreground:
        os.closerange(0, max(int(fd) for fd in os.listdir("/proc/self/fd")))
        for fd in range(3):
            null = os.open(os.path.devnull, os.O_WRONLY if fd else os.O_RDONLY)
            if fd != null:
                os.dup2(null, fd)
                os.close(null)
            os.set_inheritable(fd, True)

    # init logging
    logfile = options.logfile % {'module': options.module}
    log_init(logfile, options.debug, use_structured_logging=ucr.is_true('umc/server/debug/structured-logging'))

    univention.logging.extendLogger('tornado', univention_debug_category='NETWORK')
    logger = logging.getLogger('tornado')
    logger.set_ud_level(ucr.get_int('umc/module/tornado-debug/level', 3))

    add_filter(RequestFilter(options.module))

    try:
        locale_obj = Locale(options.language)
        locale.setlocale(locale.LC_MESSAGES, str(locale_obj))
        translation = Translation('univention-management-console')
        translation.set_language(options.language)
    except Exception:
        MODULE.error('The specified locale %r is not available', options.language)

    # this import must be done after the locale is set!
    from univention.management.console.modserver import ModuleServer

    if not options.socket:
        raise SystemError('socket name is missing')

    # make sure the directory where to place socket files exists
    if not os.path.exists('/run/univention-management-console'):
        os.mkdir('/run/univention-management-console')

    try:
        with ModuleServer(options.socket, options.module, logfile, timeout=MODULE_INACTIVITY_TIMER // 1000) as server:
            server.loop()
    except (SystemExit, KeyboardInterrupt):
        raise
    except BaseException:
        MODULE.exception("Module process crashed.")
        raise
