Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/XRDP/sesman/   (X11 Server Version 0.10.6.1©)  Datei vom 7.6.2026 mit Größe 24 kB image not shown  

Quelle  sesman.c

  Sprache: C
 

/**
 * xrdp: A Remote Desktop Protocol server.
 *
 * Copyright (C) Jay Sorg 2004-2015
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


/**
 *
 * @file sesman.c
 * @brief Main program file
 * @author Jay Sorg
 *
 */


#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif

#include <stdarg.h>

#include "arch.h"
#include "sesman.h"

#include "sesman_auth.h"
#include "sesman_config.h"
#include "eicp.h"
#include "eicp_process.h"
#include "ercp.h"
#include "ercp_process.h"
#include "pre_session_list.h"
#include "session_list.h"
#include "lock_uds.h"
#include "os_calls.h"
#include "scp.h"
#include "scp_process.h"
#include "sesexec_control.h"
#include "sig.h"
#include "string_calls.h"
#include "trans.h"
#include "xrdp_configure_options.h"
#include "xrdp_sockets.h"

/**
 * Maximum number of pre-session items
 */

#define MAX_PRE_SESSION_ITEMS 16

/**
 * Define the mode of operation of the program
 */

enum sesman_mode
{
    SSM_NORMAL = 0,
    SSM_KILL_DAEMON,
    SSM_RELOAD_DAEMON
};

struct sesman_startup_params
{
    const char *sesman_ini;
    enum sesman_mode mode;
    int no_daemon;
    int help;
    int version;
    int dump_config;
};

struct config_sesman *g_cfg;
static tintptr g_term_event = 0;
static tintptr g_sigchld_event = 0;
static tintptr g_reload_event = 0;

static struct trans *g_list_trans;

/* Variables used to lock g_list_trans */
static struct lock_uds *g_list_trans_lock;

static struct list *g_con_list = NULL;
static int g_pid;

/*****************************************************************************/
/**
 * @brief looks for a case-insensitive match of a string in a list
 * @param candidate  String to match
 * @param ... NULL-terminated list of strings to compare the candidate with
 * @return !=0 if the candidate is found in the list
 */

static int nocase_matches(const char *candidate, ...)
{
    va_list vl;
    const char *member;
    int result = 0;

    va_start(vl, candidate);
    while ((member = va_arg(vl, const char *)) != NULL)
    {
        if (g_strcasecmp(candidate, member) == 0)
        {
            result = 1;
            break;
        }
    }

    va_end(vl);
    return result;
}

/*****************************************************************************/
/**
 *
 * @brief  Command line argument parser
 * @param[in] argc number of command line arguments
 * @param[in] argv pointer array of commandline arguments
 * @param[out] sesman_startup_params Returned startup parameters
 * @return 0 on success, n on nth argument is unknown
 *
 */

static int
sesman_process_params(int argc, char **argv,
                      struct sesman_startup_params *startup_params)
{
    int index;
    const char *option;
    const char *value;

    startup_params->mode = SSM_NORMAL;

    index = 1;

    while (index < argc)
    {
        option = argv[index];

        if (index + 1 < argc)
        {
            value = argv[index + 1];
        }
        else
        {
            value = "";
        }

        if (nocase_matches(option, "-help""--help""-h", NULL))
        {
            startup_params->help = 1;
        }
        else if (nocase_matches(option, "-kill""--kill""-k", NULL))
        {
            startup_params->mode = SSM_KILL_DAEMON;
        }
        else if (nocase_matches(option, "-reload""--reload""-r", NULL))
        {
            startup_params->mode = SSM_RELOAD_DAEMON;
        }
        else if (nocase_matches(option, "-nodaemon""--nodaemon""-n",
                                "-nd""--nd""-ns""--ns", NULL))
        {
            startup_params->no_daemon = 1;
        }
        else if (nocase_matches(option, "-v""--version", NULL))
        {
            startup_params->version = 1;
        }
        else if (nocase_matches(option, "--dump-config", NULL))
        {
            startup_params->dump_config = 1;
        }
        else if (nocase_matches(option, "-c""--config", NULL))
        {
            index++;
            startup_params->sesman_ini = value;
        }
        else /* unknown option */
        {
            return index;
        }

        index++;
    }

    return 0;
}

/******************************************************************************/
static int sesman_listen_test(struct config_sesman *cfg)
{
    int status = sesman_create_listening_transport(cfg);
    sesman_delete_listening_transport();
    return status;
}

/******************************************************************************/
int
sesman_close_all(void)
{
    LOG_DEVEL(LOG_LEVEL_TRACE, "sesman_close_all:");

    pre_session_list_cleanup();
    session_list_cleanup();

    g_delete_wait_obj(g_reload_event);
    g_delete_wait_obj(g_sigchld_event);
    g_delete_wait_obj(g_term_event);

    sesman_delete_listening_transport();

    return 0;
}

/******************************************************************************/
int
sesman_scp_data_in(struct trans *self)
{
    int rv;
    int available;

    rv = scp_msg_in_check_available(self, &available);

    if (rv == 0 && available)
    {
        struct pre_session_item *psi;
        psi = (struct pre_session_item *)self->callback_data;

        if ((rv = scp_process(psi)) != 0)
        {
            LOG(LOG_LEVEL_ERROR, "sesman_data_in: scp_process_msg failed");
        }
        scp_msg_in_reset(self);
    }

    return rv;
}

/******************************************************************************/
static int
sesman_listen_conn_in(struct trans *self, struct trans *new_self)
{
    struct pre_session_item *psi;
    if (pre_session_list_get_count() >= MAX_PRE_SESSION_ITEMS)
    {
        LOG(LOG_LEVEL_ERROR, "sesman_listen_conn_in: error, too many "
            "connections, rejecting");
        trans_delete(new_self);
    }
    else if ((psi = pre_session_list_new()) == NULL)
    {
        LOG(LOG_LEVEL_ERROR, "sesman_data_in: No memory to allocate "
            "new connection");
        trans_delete(new_self);
    }
    else if (scp_init_trans(new_self) != 0)
    {
        LOG(LOG_LEVEL_ERROR, "sesman_data_in: Can't init SCP connection");
        trans_delete(new_self);
    }
    else
    {
        new_self->callback_data = (void *)psi;
        new_self->trans_data_in = sesman_scp_data_in;
        psi->client_trans = new_self;
    }

    return 0;
}

/******************************************************************************/
int
sesman_eicp_data_in(struct trans *self)
{
    int rv;
    int available;

    rv = eicp_msg_in_check_available(self, &available);

    if (rv == 0 && available)
    {
        struct pre_session_item *psi;
        psi = (struct pre_session_item *)self->callback_data;
        if ((rv = eicp_process(psi)) != 0)
        {
            LOG(LOG_LEVEL_ERROR, "sesman_eicp_data_in: eicp_process_msg failed");
        }
        eicp_msg_in_reset(self);
    }

    return rv;
}

/******************************************************************************/
int
sesman_ercp_data_in(struct trans *self)
{
    int rv;
    int available;

    rv = ercp_msg_in_check_available(self, &available);

    if (rv == 0 && available)
    {
        struct session_item *si = (struct session_item *)self->callback_data;
        if ((rv = ercp_process(si)) != 0)
        {
            LOG(LOG_LEVEL_ERROR, "sesman_ercp_data_in: ercp_process_msg failed");
        }
        ercp_msg_in_reset(self);
    }

    return rv;
}

/******************************************************************************/
/**
 * Informs the main loop a termination signal has been received
 */

static void
set_term_event(int sig)
{
    /* Don't try to use a wait obj in a child process */
    if (g_getpid() == g_pid)
    {
        g_set_wait_obj(g_term_event);
    }
}

/*****************************************************************************/
/* No-op signal handler.
 */

static void
sig_no_op(int sig)
{
    /* no-op */
}

/******************************************************************************/
/**
 * Catch a SIGCHLD and ignore the main loop
 *
 * In theory we could use waitpid() in the signal handler, but that
 * would prevent us adding any logging
 */

static void
set_sigchld_event(int sig)
{
    /* Don't try to use a wait obj in a child process */
    if (g_getpid() == g_pid)
    {
        g_set_wait_obj(g_sigchld_event);
    }
}

/******************************************************************************/
/**
 * Informs the main loop a SIGHUP has been received
 */

static void
set_reload_event(int sig)
{
    /* Don't try to use a wait obj in a child process */
    if (g_getpid() == g_pid)
    {
        g_set_wait_obj(g_reload_event);
    }
}

/******************************************************************************/
void
sesman_delete_listening_transport(void)
{
    if (g_getpid() == g_pid)
    {
        trans_delete(g_list_trans);
    }
    else
    {
        trans_delete_from_child(g_list_trans);
    }
    g_list_trans = NULL;

    unlock_uds(g_list_trans_lock); // Won't unlock anything for a child process
    g_list_trans_lock = NULL;
}

/******************************************************************************/
int
sesman_create_listening_transport(const struct config_sesman *cfg)
{
    int rv = 1;
    g_list_trans = trans_create(TRANS_MODE_UNIX, 81928192);
    if (g_list_trans == NULL)
    {
        LOG(LOG_LEVEL_ERROR, "%s: trans_create failed", __func__);
    }
    else if ((g_list_trans_lock = lock_uds(cfg->listen_port)) != NULL)
    {
        /* Make sure the file is always created with the correct
         * permissions, if it's not there */

        int entry_umask = g_umask_hex(0x666);
        LOG_DEVEL(LOG_LEVEL_DEBUG, "%s: port %s", __func__, cfg->listen_port);
        rv = trans_listen_address(g_list_trans, cfg->listen_port, NULL);
        if (rv != 0)
        {
            LOG(LOG_LEVEL_ERROR, "%s: trans_listen_address failed", __func__);
        }
        else if (g_chown(cfg->listen_port, g_getuid(), g_getuid()) != 0)
        {
            LOG(LOG_LEVEL_ERROR,
                "Can't set ownership of '%s' [%s]",
                cfg->listen_port, g_get_strerror());
        }
        else if ((rv = g_chmod_hex(cfg->listen_port, 0x666)) != 0)
        {
            LOG(LOG_LEVEL_ERROR, "%s: Can't set permissions on '%s' [%s]",
                __func__, cfg->listen_port, g_get_strerror());
        }
        else
        {
            g_list_trans->trans_conn_in = sesman_listen_conn_in;
        }
        g_umask_hex(entry_umask);
    }

    if (rv != 0)
    {
        sesman_delete_listening_transport();
    }

    return rv;
}

/******************************************************************************/
int
sesman_is_term(void)
{
    return g_is_wait_obj_set(g_term_event);
}

/******************************************************************************/
/**
 *
 * @brief Starts sesman main loop
 *
 */

static int
sesman_main_loop(void)
{
    int error;
    int robjs_count;
    intptr_t robjs[1024];

    g_con_list = list_create();
    if (g_con_list == NULL)
    {
        LOG(LOG_LEVEL_ERROR, "sesman_main_loop: list_create failed");
        return 1;
    }
    if (sesman_create_listening_transport(g_cfg) != 0)
    {
        LOG(LOG_LEVEL_ERROR,
            "sesman_main_loop: sesman_create_listening_transport failed");
        list_delete(g_con_list);
        return 1;
    }
    LOG(LOG_LEVEL_INFO, "Sesman now listening on %s", g_cfg->listen_port);

    error = 0;
    while (!error)
    {
        robjs_count = 0;
        robjs[robjs_count++] = g_term_event;
        robjs[robjs_count++] = g_sigchld_event;
        robjs[robjs_count++] = g_reload_event;

        if (g_list_trans != NULL)
        {
            /* g_list_trans might be NULL on a reconfigure if sesman
             * is unable to listen again */

            error = trans_get_wait_objs(g_list_trans, robjs, &robjs_count);
            if (error != 0)
            {
                LOG(LOG_LEVEL_ERROR, "sesman_main_loop: "
                    "trans_get_wait_objs failed");
                break;
            }
        }

        error = pre_session_list_get_wait_objs(robjs, &robjs_count);
        if (error != 0)
        {
            LOG(LOG_LEVEL_ERROR, "sesman_main_loop: "
                "pre_session_list_get_wait_objs failed");
            break;
        }

        error = session_list_get_wait_objs(robjs, &robjs_count);
        if (error != 0)
        {
            LOG(LOG_LEVEL_ERROR, "sesman_main_loop: "
                "session_list_get_wait_objs failed");
            break;
        }

        if (g_obj_wait(robjs, robjs_count, NULL, 0, -1) != 0)
        {
            /* should not get here */
            LOG(LOG_LEVEL_WARNING, "sesman_main_loop: "
                "Unexpected error from g_obj_wait()");
            g_sleep(100);
        }

        if (g_is_wait_obj_set(g_term_event)) /* term */
        {
            LOG(LOG_LEVEL_INFO, "sesman_main_loop: "
                "sesman asked to terminate");
            break;
        }

        if (g_is_wait_obj_set(g_sigchld_event)) /* term */
        {
            g_reset_wait_obj(g_sigchld_event);
            // Prevent any zombies from hanging around
            while (g_waitchild(NULL) > 0)
            {
                ;
            }
        }

        if (g_is_wait_obj_set(g_reload_event)) /* We're asked to reload */
        {
            g_reset_wait_obj(g_reload_event);
            sig_sesman_reload_cfg();
        }

        if (g_list_trans != NULL)
        {
            error = trans_check_wait_objs(g_list_trans);
            if (error != 0)
            {
                LOG(LOG_LEVEL_ERROR, "sesman_main_loop: "
                    "trans_check_wait_objs failed");
                break;
            }
        }

        error = pre_session_list_check_wait_objs();
        if (error != 0)
        {
            LOG(LOG_LEVEL_ERROR, "sesman_main_loop: "
                "pre_session_list_check_wait_objs failed");
            break;
        }

        error = session_list_check_wait_objs();
        if (error != 0)
        {
            LOG(LOG_LEVEL_ERROR, "sesman_main_loop: "
                "session_list_check_wait_objs failed");
            break;
        }
    }

    return error;
}

/*****************************************************************************/
static void
print_version(void)
{
    g_writeln("xrdp-sesman %s", PACKAGE_VERSION);
    g_writeln("  The xrdp session manager");
    g_writeln("  Copyright (C) 2004-%d Jay Sorg, "
              "Neutrino Labs, and all contributors.",
              VERSION_YEAR);
    g_writeln("  See https://github.com/neutrinolabs/xrdp for more information.");
    g_writeln("%s""");

#if defined(XRDP_CONFIGURE_OPTIONS)
    g_writeln("  Configure options:");
    g_writeln("%s", XRDP_CONFIGURE_OPTIONS);
#endif
}

/******************************************************************************/
static void
print_help(void)
{
    g_printf("Usage: xrdp-sesman [options]\n");
    g_printf("   -k, --kill        shut down xrdp-sesman\n");
    g_printf("   -r, --reload      reload xrdp-sesman\n");
    g_printf("   -h, --help        show help\n");
    g_printf("   -v, --version     show version\n");
    g_printf("   -n, --nodaemon    don't fork into background\n");
    g_printf("   -c, --config      specify new path to sesman.ini\n");
    g_printf("       --dump-config display config on stdout on startup\n");
    g_deinit();
}

/******************************************************************************/
/**
 * Reads the PID file
 */

static int
read_pid_file(const char *pid_file, int *pid)
{
    int rv = 1;
    int fd;

    /* check if sesman is running */
    if (!g_file_exist(pid_file))
    {
        g_printf("sesman is not running (pid file not found - %s)\n", pid_file);
    }
    else if ((fd = g_file_open_ro(pid_file)) < 0)
    {
        g_printf("error opening pid file[%s]: %s\n", pid_file, g_get_strerror());
    }
    else
    {
        char pid_s[32] = {0};
        int error = g_file_read(fd, pid_s, sizeof(pid_s) - 1);
        g_file_close(fd);

        if (error < 0)
        {
            g_printf("error reading pid file: %s\n", g_get_strerror());
        }
        else
        {
            *pid = g_atoi(pid_s);
            rv = 0;
        }
    }

    return rv;
}

/******************************************************************************/
/** Creates the socket path for sesman and session sockets
*/

static int
create_xrdp_socket_root_path(void)
{
    int uid = g_getuid();
    int gid = g_getgid();

    /* Create the path using 0755 permissions */
    int old_umask = g_umask_hex(0x22);
    (void)g_create_path(XRDP_SOCKET_ROOT_PATH"/");
    (void)g_umask_hex(old_umask);

    /* Check the ownership and permissions on the last path element
     * are as expected */

    if (g_chown(XRDP_SOCKET_ROOT_PATH, uid, gid) != 0)
    {
        LOG(LOG_LEVEL_ERROR,
            "create_xrdp_socket_root_path: Can't set owner of %s to %d:%d",
            XRDP_SOCKET_ROOT_PATH, uid, gid);
        return 1;
    }

    if (g_chmod_hex(XRDP_SOCKET_ROOT_PATH, 0x755) != 0)
    {
        LOG(LOG_LEVEL_ERROR,
            "create_xrdp_socket_root_path: Can't set perms of %s to 0x755",
            XRDP_SOCKET_ROOT_PATH);
        return 1;
    }

    return 0;
}

/******************************************************************************/
int
main(int argc, char **argv)
{
    int error;
    enum logReturns log_error;
    char text[256];
    char pid_file[256];
    struct sesman_startup_params startup_params = {0};
    int errored_argc;
    int daemon;

    g_init("xrdp-sesman");
    g_snprintf(pid_file, 255"%s/xrdp-sesman.pid", XRDP_PID_PATH);

    startup_params.sesman_ini = DEFAULT_SESMAN_INI;

    errored_argc = sesman_process_params(argc, argv, &startup_params);
    if (errored_argc > 0)
    {
        print_version();
        g_writeln("%s""");
        print_help();
        g_writeln("%s""");

        g_writeln("Unknown option: %s", argv[errored_argc]);
        g_deinit();
        g_exit(1);
    }

    if (startup_params.help)
    {
        print_help();
        g_exit(0);
    }

    if (startup_params.version)
    {
        print_version();
        g_exit(0);
    }


    if (startup_params.mode == SSM_KILL_DAEMON)
    {
        int pid;
        int error = 1;
        if (read_pid_file(pid_file, &pid) == 0)
        {
            if (g_sigterm(pid) != 0)
            {
                g_printf("error killing sesman: %s\n", g_get_strerror());
            }
            else
            {
                /* File is no longer required */
                g_file_delete(pid_file);
                error = 0;
            }
        }
        g_deinit();
        g_exit(error);
    }

    if (startup_params.mode == SSM_RELOAD_DAEMON)
    {
        int pid;
        int error = 1;
        if (read_pid_file(pid_file, &pid) == 0)
        {
            if (g_sighup(pid) != 0)
            {
                g_printf("error reloading sesman: %s\n", g_get_strerror());
            }
            else
            {
                error = 0;
            }
        }
        g_deinit();
        g_exit(error);
    }

    if (g_file_exist(pid_file))
    {
        g_printf("xrdp-sesman is already running.\n");
        g_printf("if it's not running, try removing ");
        g_printf("%s", pid_file);
        g_printf("\n");
        g_deinit();
        g_exit(1);
    }

    /* starting logging subsystem */
    if (!g_file_exist(startup_params.sesman_ini))
    {
        g_printf("Config file %s does not exist\n", startup_params.sesman_ini);
        g_deinit();
        g_exit(1);
    }
    log_error = log_start(
                    startup_params.sesman_ini, "xrdp-sesman",
                    (startup_params.dump_config) ? LOG_START_DUMP_CONFIG : 0);

    if (log_error != LOG_STARTUP_OK)
    {
        switch (log_error)
        {
            case LOG_ERROR_MALLOC:
                g_writeln("error on malloc. cannot start logging. quitting.");
                break;
            case LOG_ERROR_FILE_OPEN:
                g_writeln("error opening log file [%s]. quitting.",
                          getLogFile(text, 255));
                break;
            default:
                // Assume sufficient messages have already been generated
                break;
        }

        g_deinit();
        g_exit(1);
    }

    /* reading config */
    if ((g_cfg = config_read(startup_params.sesman_ini)) == NULL)
    {
        LOG(LOG_LEVEL_ALWAYS, "error reading config %s: %s",
            startup_params.sesman_ini, g_get_strerror());
        log_end();
        g_deinit();
        g_exit(1);
    }

    if (startup_params.dump_config)
    {
        config_dump(g_cfg);
    }

    LOG(LOG_LEVEL_TRACE, "config loaded in %s at %s:%d", __func__, __FILE__, __LINE__);
    LOG(LOG_LEVEL_TRACE, "    sesman_ini        = %s", g_cfg->sesman_ini);
    LOG(LOG_LEVEL_TRACE, "    listen_port       = %s", g_cfg->listen_port);
    LOG(LOG_LEVEL_TRACE, "    enable_user_wm    = %d", g_cfg->enable_user_wm);
    LOG(LOG_LEVEL_TRACE, "    default_wm        = %s", g_cfg->default_wm);
    LOG(LOG_LEVEL_TRACE, "    user_wm           = %s", g_cfg->user_wm);
    LOG(LOG_LEVEL_TRACE, "    reconnect_sh      = %s", g_cfg->reconnect_sh);
    LOG(LOG_LEVEL_TRACE, "    auth_file_path    = %s", g_cfg->auth_file_path);

    daemon = !startup_params.no_daemon;
    if (daemon)
    {
        /* not to spit on the console, shut up stdout/stderr before anything's logged */
        g_file_close(0);
        g_file_close(1);
        g_file_close(2);

        if (g_file_open_rw("/dev/null") < 0)
        {
        }

        if (g_file_open_rw("/dev/null") < 0)
        {
        }

        if (g_file_open_rw("/dev/null") < 0)
        {
        }
    }

    /* Create the socket directory before we try to listen (or
     * test-listen), so there's somewhere for the default socket to live */

    if (create_xrdp_socket_root_path() != 0)
    {
        config_free(g_cfg);
        log_end();
        g_deinit();
        g_exit(1);
    }

    if (daemon)
    {
        /* start of daemonizing code */
        if (sesman_listen_test(g_cfg) != 0)
        {
            LOG(LOG_LEVEL_ERROR, "Failed to start xrdp-sesman daemon, "
                "possibly address already in use.");
            config_free(g_cfg);
            log_end();
            g_deinit();
            g_exit(1);
        }

        if (0 != g_fork())
        {
            config_free(g_cfg);
            log_end();
            g_deinit();
            g_exit(0);
        }

    }

    /* Now we've forked (if necessary), we can get the program PID */
    g_pid = g_getpid();

    /* signal handling */
    g_snprintf(text, 255"xrdp_sesman_%8.8x_main_term", g_pid);
    g_term_event = g_create_wait_obj(text);
    g_snprintf(text, 255"xrdp_sesman_%8.8x_sigchld", g_pid);
    g_sigchld_event = g_create_wait_obj(text);
    g_snprintf(text, 255"xrdp_sesman_%8.8x_reload", g_pid);
    g_reload_event = g_create_wait_obj(text);

    g_signal_user_interrupt(set_term_event); /* SIGINT  */
    g_signal_terminate(set_term_event); /* SIGTERM */
    g_signal_pipe(sig_no_op);          /* SIGPIPE */
    g_signal_child_stop(set_sigchld_event); /* SIGCHLD */
    g_signal_hang_up(set_reload_event); /* SIGHUP  */

    if (daemon)
    {
        /* writing pid file */
        char pid_s[32];
        int fd = g_file_open_rw(pid_file);

        if (-1 == fd)
        {
            LOG(LOG_LEVEL_ERROR,
                "error opening pid file[%s]: %s",
                pid_file, g_get_strerror());
            log_end();
            config_free(g_cfg);
            g_deinit();
            g_exit(1);
        }

        g_sprintf(pid_s, "%d", g_pid);
        g_file_write(fd, pid_s, g_strlen(pid_s));
        g_file_close(fd);
    }

    /* start program main loop */
    LOG(LOG_LEVEL_INFO,
        "starting xrdp-sesman with pid %d", g_pid);

    /* make sure the X11_UNIX_SOCKET_DIRECTORY exists */
    if (!g_directory_exist(X11_UNIX_SOCKET_DIRECTORY))
    {
        if (!g_create_dir(X11_UNIX_SOCKET_DIRECTORY))
        {
            LOG(LOG_LEVEL_ERROR,
                "sesman.c: error creating dir " X11_UNIX_SOCKET_DIRECTORY);
        }
        if (g_chmod_hex(X11_UNIX_SOCKET_DIRECTORY, 0x1777) != 0)
        {
            LOG(LOG_LEVEL_ERROR,
                "sesman.c: can't set permissions on "
                X11_UNIX_SOCKET_DIRECTORY "[%s]", g_get_strerror());
        }
    }

    if ((error = pre_session_list_init(MAX_PRE_SESSION_ITEMS)) == 0 &&
            (error = session_list_init()) == 0)
    {
        error = sesman_main_loop();
    }

    /* clean up PID file on exit */
    if (daemon)
    {
        g_file_delete(pid_file);
    }

    sesman_close_all();

    log_end();

    config_free(g_cfg);
    g_deinit();
    g_exit(error);
    return 0;
}

Messung V0.5 in Prozent
C=91 H=90 G=90

¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet am  2026-07-10) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.