From 0f33f9d1535a1384f97c0a4948c95447aa1e400a Mon Sep 17 00:00:00 2001 From: simon Date: Sat, 2 Nov 2002 14:35:57 +0000 Subject: [PATCH] RJK's general signal-handling robustness patch. Should fix the weird spin behaviour occasionally seen after pterm's child process dies. git-svn-id: svn://svn.tartarus.org/sgt/putty@2181 cda61777-01e9-0310-a592-d414129be87e --- Recipe | 2 +- unix/pterm.c | 19 ++++++++++++++++ unix/pty.c | 72 ++++++++++++++++++++++++++++++----------------------------- unix/signal.c | 31 +++++++++++++++++++++++++ unix/unix.h | 3 +++ 5 files changed, 91 insertions(+), 36 deletions(-) create mode 100644 unix/signal.c diff --git a/Recipe b/Recipe index 25670e33..99a72941 100644 --- a/Recipe +++ b/Recipe @@ -137,6 +137,6 @@ puttygen : [G] puttygen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version + sshpubk sshaes sshsh512 import winutils puttygen.res LIBS pterm : [X] pterm terminal wcwidth uxucs uxmisc tree234 misc ldisc ldiscucs - + logging uxprint settings pty be_none uxstore + + logging uxprint settings pty be_none uxstore signal plink : [U] uxplink uxcons NONSSH UXSSH be_all logging UXMISC diff --git a/unix/pterm.c b/unix/pterm.c index cc459625..94b732de 100644 --- a/unix/pterm.c +++ b/unix/pterm.c @@ -1927,12 +1927,27 @@ int do_cmdline(int argc, char **argv, int do_everything) return err; } +static void block_signal(int sig, int block_it) { + sigset_t ss; + + sigemptyset(&ss); + sigaddset(&ss, sig); + if(sigprocmask(block_it ? SIG_BLOCK : SIG_UNBLOCK, &ss, 0) < 0) { + perror("sigprocmask"); + exit(1); + } +} + int main(int argc, char **argv) { extern int pty_master_fd; /* declared in pty.c */ extern void pty_pre_init(void); /* declared in pty.c */ struct gui_data *inst; + /* defer any child exit handling until we're ready to deal with + * it */ + block_signal(SIGCHLD, 1); + pty_pre_init(); gtk_init(&argc, &argv); @@ -2090,6 +2105,10 @@ int main(int argc, char **argv) inst->master_func_id = gdk_input_add(pty_master_fd, GDK_INPUT_READ, pty_input_func, inst); + /* now we're reday to deal with the child exit handler being + * called */ + block_signal(SIGCHLD, 0); + gtk_main(); return 0; diff --git a/unix/pty.c b/unix/pty.c index fd7a93c9..8bd20fec 100644 --- a/unix/pty.c +++ b/unix/pty.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "putty.h" @@ -74,8 +75,8 @@ static int pty_stamped_utmp = 0; static int pty_child_pid; static int pty_utmp_helper_pid, pty_utmp_helper_pipe; static int pty_term_width, pty_term_height; -static sig_atomic_t pty_child_dead; -static int pty_exit_code; +static volatile sig_atomic_t pty_child_dead; +static volatile int pty_exit_code; #ifndef OMIT_UTMP static struct utmp utmp_entry; #endif @@ -163,18 +164,21 @@ static void cleanup_utmp(void) static void sigchld_handler(int signum) { + int save_errno = errno; pid_t pid; int status; + pid = waitpid(-1, &status, WNOHANG); if (pid == pty_child_pid && (WIFEXITED(status) || WIFSIGNALED(status))) { pty_exit_code = status; pty_child_dead = TRUE; } + errno = save_errno; } static void fatal_sig_handler(int signum) { - signal(signum, SIG_DFL); + putty_signal(signum, SIG_DFL); cleanup_utmp(); setuid(getuid()); raise(signum); @@ -254,6 +258,9 @@ void pty_pre_init(void) pid_t pid; int pipefd[2]; + /* set the child signal handler straight away; it needs to be set + * before we ever fork. */ + putty_signal(SIGCHLD, sigchld_handler); pty_master_fd = -1; if (geteuid() != getuid() || getegid() != getgid()) { @@ -289,7 +296,7 @@ void pty_pre_init(void) ret = read(pipefd[0], buffer, lenof(buffer)); if (ret <= 0) { cleanup_utmp(); - exit(0); + _exit(0); } else if (!pty_stamped_utmp) { if (dlen < lenof(display)) memcpy(display+dlen, buffer, @@ -307,47 +314,45 @@ void pty_pre_init(void) * unfortunately unprotected against SIGKILL, * but that's life. */ - signal(SIGHUP, fatal_sig_handler); - signal(SIGINT, fatal_sig_handler); - signal(SIGQUIT, fatal_sig_handler); - signal(SIGILL, fatal_sig_handler); - signal(SIGABRT, fatal_sig_handler); - signal(SIGFPE, fatal_sig_handler); - signal(SIGPIPE, fatal_sig_handler); - signal(SIGALRM, fatal_sig_handler); - signal(SIGTERM, fatal_sig_handler); - signal(SIGSEGV, fatal_sig_handler); - signal(SIGUSR1, fatal_sig_handler); - signal(SIGUSR2, fatal_sig_handler); + putty_signal(SIGHUP, fatal_sig_handler); + putty_signal(SIGINT, fatal_sig_handler); + putty_signal(SIGQUIT, fatal_sig_handler); + putty_signal(SIGILL, fatal_sig_handler); + putty_signal(SIGABRT, fatal_sig_handler); + putty_signal(SIGFPE, fatal_sig_handler); + putty_signal(SIGPIPE, fatal_sig_handler); + putty_signal(SIGALRM, fatal_sig_handler); + putty_signal(SIGTERM, fatal_sig_handler); + putty_signal(SIGSEGV, fatal_sig_handler); + putty_signal(SIGUSR1, fatal_sig_handler); + putty_signal(SIGUSR2, fatal_sig_handler); #ifdef SIGBUS - signal(SIGBUS, fatal_sig_handler); + putty_signal(SIGBUS, fatal_sig_handler); #endif #ifdef SIGPOLL - signal(SIGPOLL, fatal_sig_handler); + putty_signal(SIGPOLL, fatal_sig_handler); #endif #ifdef SIGPROF - signal(SIGPROF, fatal_sig_handler); + putty_signal(SIGPROF, fatal_sig_handler); #endif #ifdef SIGSYS - signal(SIGSYS, fatal_sig_handler); + putty_signal(SIGSYS, fatal_sig_handler); #endif #ifdef SIGTRAP - signal(SIGTRAP, fatal_sig_handler); + putty_signal(SIGTRAP, fatal_sig_handler); #endif #ifdef SIGVTALRM - signal(SIGVTALRM, fatal_sig_handler); + putty_signal(SIGVTALRM, fatal_sig_handler); #endif #ifdef SIGXCPU - signal(SIGXCPU, fatal_sig_handler); + putty_signal(SIGXCPU, fatal_sig_handler); #endif #ifdef SIGXFSZ - signal(SIGXFSZ, fatal_sig_handler); + putty_signal(SIGXFSZ, fatal_sig_handler); #endif #ifdef SIGIO - signal(SIGIO, fatal_sig_handler); + putty_signal(SIGIO, fatal_sig_handler); #endif - /* Also clean up utmp on normal exit. */ - atexit(cleanup_utmp); setup_utmp(pty_name, display); } } @@ -356,7 +361,6 @@ void pty_pre_init(void) close(pipefd[0]); pty_utmp_helper_pid = pid; pty_utmp_helper_pipe = pipefd[1]; - signal(SIGCHLD, sigchld_handler); } #endif @@ -447,7 +451,7 @@ static char *pty_init(void *frontend, void **backend_handle, slavefd = open(pty_name, O_RDWR); if (slavefd < 0) { perror("slave pty: open"); - exit(1); + _exit(1); } close(pty_master_fd); @@ -475,8 +479,8 @@ static char *pty_init(void *frontend, void **backend_handle, * parent, particularly by things like sh -c 'pterm &' and * some window managers. Reverse this for our child process. */ - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); + putty_signal(SIGINT, SIG_DFL); + putty_signal(SIGQUIT, SIG_DFL); if (pty_argv) execvp(pty_argv[0], pty_argv); else { @@ -496,13 +500,11 @@ static char *pty_init(void *frontend, void **backend_handle, * If we're here, exec has gone badly foom. */ perror("exec"); - exit(127); + _exit(127); } else { - close(slavefd); pty_child_pid = pid; pty_child_dead = FALSE; - signal(SIGCHLD, sigchld_handler); - } + } return NULL; } diff --git a/unix/signal.c b/unix/signal.c new file mode 100644 index 00000000..4e103b73 --- /dev/null +++ b/unix/signal.c @@ -0,0 +1,31 @@ +#include + +/* + * Calling signal() is a non-portable, as it varies in meaning between + * platforms and depending on feature macros, and has stupid semantics + * at least some of the time. + * + * This function provides the same interface as the libc function, but + * provides consistent semantics. It assumes POSIX semantics for + * sigaction() (so you might need to do some more work if you port to + * something ancient like SunOS 4) + */ +void (*putty_signal(int sig, void (*func)(int)))(int) { + struct sigaction sa; + struct sigaction old; + + sa.sa_handler = func; + if(sigemptyset(&sa.sa_mask) < 0) + return SIG_ERR; + sa.sa_flags = SA_RESTART; + if(sigaction(sig, &sa, &old) < 0) + return SIG_ERR; + return old.sa_handler; +} + +/* +Local Variables: +c-basic-offset:4 +comment-column:40 +End: +*/ diff --git a/unix/unix.h b/unix/unix.h index 534bf92f..dc2f3c4d 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -50,4 +50,7 @@ int next_socket(int *state, int *rwx); #define strnicmp strncasecmp #define stricmp strcasecmp +/* BSD-semantics version of signal() */ +void (*putty_signal(int sig, void (*func)(int)))(int); + #endif -- 2.11.0