Subversion Repositories Code-Repo

Rev

Blame | Last modification | View Log | RSS feed

/*
 * esh - the 'extensible' shell.
 *
 * Utility functions for system calls.
 *
 * Developed by Godmar Back for CS 3214 Fall 2009
 * Virginia Tech.
 */

#include <termios.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <assert.h>

#include "esh-sys-utils.h"

static const char rcsid [] = "$Id: esh-sys-utils.c,v 1.4 2011/01/21 20:13:06 cs3214 Exp $";

/* Utility function for esh_sys_fatal_error and esh_sys_error */
static void 
vesh_sys_error(char *fmt, va_list ap)
{
    char errmsg[1024];

    strerror_r(errno, errmsg, sizeof errmsg);
    vfprintf(stderr, fmt, ap);
    fprintf(stderr, "%s\n", errmsg);
}

/* Print information about the last syscall error */
void 
esh_sys_error(char *fmt, ...) 
{
    va_list ap;
    va_start(ap, fmt);
    vesh_sys_error(fmt, ap);
    va_end(ap);
}

/* Print information about the last syscall error and then exit */
void
esh_sys_fatal_error(char *fmt, ...) 
{
    va_list ap;
    va_start(ap, fmt);
    vesh_sys_error(fmt, ap);
    va_end(ap);
    exit(EXIT_FAILURE);
}

static int terminal_fd = -1;           /* the controlling terminal */
static struct termios saved_tty_state;  /* the state of the terminal when shell
                                           was started. */

/* Initialize tty support.  Return pointer to saved initial terminal state */
struct termios *
esh_sys_tty_init(void)
{
    char *tty;
    assert(terminal_fd == -1 || !!!"esh_sys_tty_init already called");

    terminal_fd = open(tty = ctermid(NULL), O_RDWR);
    if (terminal_fd == -1)
        esh_sys_fatal_error("opening controlling terminal %s failed: ", tty);

    esh_sys_tty_save(&saved_tty_state);
    return &saved_tty_state;
}

/* Save current terminal settings.
 * This function is used when a job is suspended.*/
void 
esh_sys_tty_save(struct termios *saved_tty_state)
{
    int rc = tcgetattr(terminal_fd, saved_tty_state);
    if (rc == -1)
        esh_sys_fatal_error("tcgetattr failed: ");
}

/* Restore terminal to saved settings.
 * This function is used when resuming a suspended job. */
void
esh_sys_tty_restore(struct termios *saved_tty_state)
{
    int rc = tcsetattr(terminal_fd, TCSADRAIN, saved_tty_state);
    if (rc == -1)
        esh_sys_fatal_error("could not restore tty attributes tcsetattr: ");
}

/* Get a file descriptor that refers to controlling terminal */
int 
esh_sys_tty_getfd(void)
{
    assert(terminal_fd != -1 || !!!"esh_sys_tty_init() must be called");
    return terminal_fd;
}

/* Return true if this signal is blocked */
bool 
esh_signal_is_blocked(int sig)
{
    sigset_t mask;
    if (sigprocmask(0, NULL, &mask) == -1)
        esh_sys_error("sigprocmask failed while retrieving current mask");

    return sigismember(&mask, sig);
}

/* Helper for esh_signal_block and esh_signal_unblock */
static bool
__mask_signal(int sig, int how)
{
    sigset_t mask, omask;
    sigemptyset(&mask);
    sigaddset(&mask, sig);
    if (sigprocmask(how, &mask, &omask) != 0)
        esh_sys_error("sigprocmask failed for %d/%d", sig, how);
    return sigismember(&omask, sig);
}

/* Block a signal. Returns true it was blocked before */
bool 
esh_signal_block(int sig)
{
    return __mask_signal(sig, SIG_BLOCK);
}

/* Unblock a signal. Returns true it was blocked before */
bool 
esh_signal_unblock(int sig)
{
    return __mask_signal(sig, SIG_UNBLOCK);
}

/* Install signal handler for signal 'sig' */
void
esh_signal_sethandler(int sig, sa_sigaction_t handler)
{
    sigset_t emptymask;

    sigemptyset(&emptymask);
    struct sigaction sa = {
        .sa_sigaction = handler,
        /* do not block any additional signals (besides 'sig') when
         * signal handler is entered. */
        .sa_mask = emptymask,
        /* restart system calls when possible */
        .sa_flags = SA_RESTART | SA_SIGINFO
    };

    if (sigaction(sig, &sa, NULL) != 0)
        esh_sys_fatal_error("sigaction failed for signal %d", sig);
}