ksh/sigexec.c
2012-01-24 16:09:02 +00:00

164 lines
3.6 KiB
C

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <errno.h>
#include <limits.h>
#include <pty.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>
static sig_atomic_t died;
static void sigchld(int sig __attribute__((__unused__)))
{
const int old_errno = errno;
int status;
pid_t pid;
while ((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) != 0) {
if (errno == ECHILD)
break;
if (pid < 0)
continue;
died = 1;
}
errno = old_errno;
}
static pid_t pid = -1;
static void sigother(int sig)
{
printf("%s\n", strsignal(sig));
if (sig == SIGINT)
sig = SIGTERM;
if (pid > 0) kill(pid, sig);
}
int main(int argc, char* argv[])
{
int ptm, pts;
ssize_t len;
static struct termios o;
static struct winsize w;
char ptsname[NAME_MAX+1];
char buffer[65536];
sigset_t set;
struct sigaction sa;
if (ioctl(0, TIOCGWINSZ, &w) < 0) {
w.ws_row = 24;
w.ws_col = 160;
errno = 0;
}
if (tcgetattr(0, &o) < 0) {
cfmakeraw(&o);
cfsetispeed(&o, B38400);
cfsetospeed(&o, B38400);
}
o.c_lflag &= ~ECHO;
o.c_lflag |= ISIG;
o.c_cc[VTIME] = 0;
o.c_cc[VMIN] = CMIN;
if (openpty(&ptm, &pts, ptsname, &o, &w) < 0)
perror("pty: can not open pty/tty pair");
(void)sigemptyset(&set);
(void)sigaddset(&set, SIGCHLD);
sigprocmask(SIG_UNBLOCK, &set, (sigset_t*)0);
sa.sa_flags = SA_RESTART;
sa.sa_handler = sigchld;
sigemptyset (&sa.sa_mask);
sigaction(SIGCHLD, &sa, (struct sigaction*)0);
(void)sigemptyset(&set);
(void)sigaddset(&set, SIGTERM);
sigprocmask(SIG_UNBLOCK, &set, (sigset_t*)0);
sa.sa_flags = SA_RESTART;
sa.sa_handler = sigother;
sigemptyset (&sa.sa_mask);
sigaction(SIGTERM, &sa, (struct sigaction*)0);
(void)sigemptyset(&set);
(void)sigaddset(&set, SIGHUP);
sigprocmask(SIG_UNBLOCK, &set, (sigset_t*)0);
sa.sa_flags = SA_RESTART;
sa.sa_handler = sigother;
sigemptyset (&sa.sa_mask);
sigaction(SIGHUP, &sa, (struct sigaction*)0);
switch ((pid = fork())) {
case 0:
ioctl(1, TIOCNOTTY);
if (setsid() < 0)
perror("pty: can not get controlling tty");
dup2(pts, 1);
dup2(pts, 2);
close(pts);
close(ptm);
if (ioctl (1, TIOCSCTTY, 1) < 0)
perror("pty: can not get controlling tty");
break;
case -1:
close(pts);
close(ptm);
perror("pty: can not fork");
exit(1);
default:
dup2(ptm, 0);
close(pts);
close(ptm);
while ((len = read(0, buffer, sizeof(buffer)))) {
ssize_t p = 0;
const char* ptr = buffer;
while (len > 0) {
p = write(1, ptr, len);
if (p < 0) {
if (errno == EPIPE)
exit (0);
if (errno == EINTR || errno == EAGAIN)
continue;
return 1;
}
ptr += p;
len -= p;
}
if (died)
break;
}
return 0;
}
(void)sigfillset(&set);
sigprocmask(SIG_UNBLOCK, &set, (sigset_t*)0);
(void)sigemptyset(&set);
(void)sigaddset(&set, SIGCHLD);
sigprocmask(SIG_BLOCK, &set, (sigset_t*)0);
sa.sa_flags = SA_RESTART;
sa.sa_handler = SIG_DFL;
sigemptyset (&sa.sa_mask);
sigaction(SIGHUP, &sa, (struct sigaction*)0);
sigaction(SIGPIPE, &sa, (struct sigaction*)0);
sigaction(SIGTERM, &sa, (struct sigaction*)0);
sigaction(SIGURG, &sa, (struct sigaction*)0);
sigaction(SIGXFSZ, &sa, (struct sigaction*)0);
sigaction(SIGQUIT, &sa, (struct sigaction*)0);
sa.sa_handler = SIG_IGN;
sigaction(SIGINT, &sa, (struct sigaction*)0);
sigaction(SIGQUIT, &sa, (struct sigaction*)0);
return execv(argv[0], &argv[1]);
}