signals.c
author viric@mandarina
Mon, 28 Apr 2008 21:37:25 +0200
changeset 90 f172b95795d8
parent 84 150a622f26ea
permissions -rw-r--r--
Moving to version 0.4.1

/*
    Terminal Mixer - multi-point multi-user access to terminal applications
    Copyright (C) 2007  LluĂ­s Batlle i Rossell

    Please find the license in the provided COPYING file.
*/
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h>

#include "main.h"
#include "handlers.h"

static int child;
int child_died;
static char old_alarm_handler_set;
static struct sigaction old_alarm_handler;

static int timeout_timed_out; 

static void forward_signals_to_child_handler(int val)
{
    kill(child, val);
}

static void sig_child_died(int val)
{
    int status; 
    int res;

    assert(child_died == 0);

    res = wait(&status);

    if (WIFEXITED(status) || WIFSIGNALED(status))
    {
        debugmsg("Child exited");
        child_died = 1;
    }
    debugmsg("Child handler");
}

static void update_window_size(int val)
{
    char *xterm_str;
    int len;

    pass_winsize_to_slave();

    kill(child, val);

    /* Resend the xterm string */
    xterm_str = get_xterm_resize_string();
    len = strlen(xterm_str);
    if (command_line.s_param.serve_unix)
        s_unix_send_to_connected(xterm_str, len);
    if (command_line.s_param.serve_tcp)
        s_tcp_send_to_connected(xterm_str, len);
#ifdef linux
    if (command_line.s_param.serve_eth)
        s_eth_send_to_connected(xterm_str, len);
#endif /* linux */
}

void install_signal_forwarders(int _child)
{
    struct sigaction act;

    child = _child;

    act.sa_handler = forward_signals_to_child_handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;

    sigaction(SIGTERM, &act, 0);
    sigaction(SIGINT, &act, 0);

    act.sa_handler = update_window_size;
    sigaction(SIGWINCH, &act, 0);

    act.sa_handler = sig_child_died;
    act.sa_flags = SA_NOCLDSTOP;
    sigaction(SIGCHLD, &act, 0);
}

static void alarm_handler(int x)
{
    timeout_timed_out = 1;
    dump_line("Timeout timed out.");
}

void program_timeout(int secs)
{
    struct sigaction act;
    struct sigaction *old;
    int res;

    dump_line("Programming timeout for %i seconds.\n", secs);

    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    act.sa_handler = alarm_handler;

    if (old_alarm_handler_set)
        old = 0;
    else
        old = &old_alarm_handler;

    res = sigaction(SIGALRM, &act, old);
    if (res == -1)
        error("Sigaction SIGALRM failed");

    old_alarm_handler_set = 1;
    timeout_timed_out = 0;

    alarm(secs);
}

int did_timeout_happen()
{
    return timeout_timed_out;
}

void unprogram_timeout()
{
    alarm(0);

    dump_line("Unprogramming timeout");

    timeout_timed_out = 0;

    if (old_alarm_handler_set)
    {
        sigaction(SIGALRM, &old_alarm_handler, 0);
        old_alarm_handler_set = 0;
    }
}

void ignore_sighup()
{
    struct sigaction act;

    act.sa_handler = SIG_IGN;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;

    sigaction(SIGHUP, &act, 0);
}