Subversion Repositories Code-Repo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
141 Kevin 1
/*
2
 * esh - the 'extensible' shell.
3
 *
4
 * Utility functions for system calls.
5
 *
6
 * Developed by Godmar Back for CS 3214 Fall 2009
7
 * Virginia Tech.
8
 */
9
 
10
#include <termios.h>
11
#include <stdio.h>
12
#include <errno.h>
13
#include <string.h>
14
#include <stdarg.h>
15
#include <unistd.h>
16
#include <fcntl.h>
17
#include <stdlib.h>
18
#include <signal.h>
19
#include <assert.h>
20
 
21
#include "esh-sys-utils.h"
22
 
23
static const char rcsid [] = "$Id: esh-sys-utils.c,v 1.4 2011/01/21 20:13:06 cs3214 Exp $";
24
 
25
/* Utility function for esh_sys_fatal_error and esh_sys_error */
26
static void 
27
vesh_sys_error(char *fmt, va_list ap)
28
{
29
    char errmsg[1024];
30
 
31
    strerror_r(errno, errmsg, sizeof errmsg);
32
    vfprintf(stderr, fmt, ap);
33
    fprintf(stderr, "%s\n", errmsg);
34
}
35
 
36
/* Print information about the last syscall error */
37
void 
38
esh_sys_error(char *fmt, ...) 
39
{
40
    va_list ap;
41
    va_start(ap, fmt);
42
    vesh_sys_error(fmt, ap);
43
    va_end(ap);
44
}
45
 
46
/* Print information about the last syscall error and then exit */
47
void
48
esh_sys_fatal_error(char *fmt, ...) 
49
{
50
    va_list ap;
51
    va_start(ap, fmt);
52
    vesh_sys_error(fmt, ap);
53
    va_end(ap);
54
    exit(EXIT_FAILURE);
55
}
56
 
57
static int terminal_fd = -1;           /* the controlling terminal */
58
static struct termios saved_tty_state;  /* the state of the terminal when shell
59
                                           was started. */
60
 
61
/* Initialize tty support.  Return pointer to saved initial terminal state */
62
struct termios *
63
esh_sys_tty_init(void)
64
{
65
    char *tty;
66
    assert(terminal_fd == -1 || !!!"esh_sys_tty_init already called");
67
 
68
    terminal_fd = open(tty = ctermid(NULL), O_RDWR);
69
    if (terminal_fd == -1)
70
        esh_sys_fatal_error("opening controlling terminal %s failed: ", tty);
71
 
72
    esh_sys_tty_save(&saved_tty_state);
73
    return &saved_tty_state;
74
}
75
 
76
/* Save current terminal settings.
77
 * This function is used when a job is suspended.*/
78
void 
79
esh_sys_tty_save(struct termios *saved_tty_state)
80
{
81
    int rc = tcgetattr(terminal_fd, saved_tty_state);
82
    if (rc == -1)
83
        esh_sys_fatal_error("tcgetattr failed: ");
84
}
85
 
86
/* Restore terminal to saved settings.
87
 * This function is used when resuming a suspended job. */
88
void
89
esh_sys_tty_restore(struct termios *saved_tty_state)
90
{
91
    int rc = tcsetattr(terminal_fd, TCSADRAIN, saved_tty_state);
92
    if (rc == -1)
93
        esh_sys_fatal_error("could not restore tty attributes tcsetattr: ");
94
}
95
 
96
/* Get a file descriptor that refers to controlling terminal */
97
int 
98
esh_sys_tty_getfd(void)
99
{
100
    assert(terminal_fd != -1 || !!!"esh_sys_tty_init() must be called");
101
    return terminal_fd;
102
}
103
 
104
/* Return true if this signal is blocked */
105
bool 
106
esh_signal_is_blocked(int sig)
107
{
108
    sigset_t mask;
109
    if (sigprocmask(0, NULL, &mask) == -1)
110
        esh_sys_error("sigprocmask failed while retrieving current mask");
111
 
112
    return sigismember(&mask, sig);
113
}
114
 
115
/* Helper for esh_signal_block and esh_signal_unblock */
116
static bool
117
__mask_signal(int sig, int how)
118
{
119
    sigset_t mask, omask;
120
    sigemptyset(&mask);
121
    sigaddset(&mask, sig);
122
    if (sigprocmask(how, &mask, &omask) != 0)
123
        esh_sys_error("sigprocmask failed for %d/%d", sig, how);
124
    return sigismember(&omask, sig);
125
}
126
 
127
/* Block a signal. Returns true it was blocked before */
128
bool 
129
esh_signal_block(int sig)
130
{
131
    return __mask_signal(sig, SIG_BLOCK);
132
}
133
 
134
/* Unblock a signal. Returns true it was blocked before */
135
bool 
136
esh_signal_unblock(int sig)
137
{
138
    return __mask_signal(sig, SIG_UNBLOCK);
139
}
140
 
141
/* Install signal handler for signal 'sig' */
142
void
143
esh_signal_sethandler(int sig, sa_sigaction_t handler)
144
{
145
    sigset_t emptymask;
146
 
147
    sigemptyset(&emptymask);
148
    struct sigaction sa = {
149
        .sa_sigaction = handler,
150
        /* do not block any additional signals (besides 'sig') when
151
         * signal handler is entered. */
152
        .sa_mask = emptymask,
153
        /* restart system calls when possible */
154
        .sa_flags = SA_RESTART | SA_SIGINFO
155
    };
156
 
157
    if (sigaction(sig, &sa, NULL) != 0)
158
        esh_sys_fatal_error("sigaction failed for signal %d", sig);
159
}