1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-03-22 14:39:24 -05:00

RJK's general signal-handling robustness patch. Should fix the weird

spin behaviour occasionally seen after pterm's child process dies.

[originally from svn r2181]
This commit is contained in:
Simon Tatham 2002-11-02 14:35:57 +00:00
parent 406bc897b3
commit 93e9fadc75
5 changed files with 91 additions and 36 deletions

2
Recipe
View File

@ -137,6 +137,6 @@ puttygen : [G] puttygen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version
+ sshpubk sshaes sshsh512 import winutils puttygen.res LIBS + sshpubk sshaes sshsh512 import winutils puttygen.res LIBS
pterm : [X] pterm terminal wcwidth uxucs uxmisc tree234 misc ldisc ldiscucs 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 plink : [U] uxplink uxcons NONSSH UXSSH be_all logging UXMISC

View File

@ -1927,12 +1927,27 @@ int do_cmdline(int argc, char **argv, int do_everything)
return err; 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) int main(int argc, char **argv)
{ {
extern int pty_master_fd; /* declared in pty.c */ extern int pty_master_fd; /* declared in pty.c */
extern void pty_pre_init(void); /* declared in pty.c */ extern void pty_pre_init(void); /* declared in pty.c */
struct gui_data *inst; struct gui_data *inst;
/* defer any child exit handling until we're ready to deal with
* it */
block_signal(SIGCHLD, 1);
pty_pre_init(); pty_pre_init();
gtk_init(&argc, &argv); 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, inst->master_func_id = gdk_input_add(pty_master_fd, GDK_INPUT_READ,
pty_input_func, inst); pty_input_func, inst);
/* now we're reday to deal with the child exit handler being
* called */
block_signal(SIGCHLD, 0);
gtk_main(); gtk_main();
return 0; return 0;

View File

@ -29,6 +29,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <errno.h>
#include "putty.h" #include "putty.h"
@ -74,8 +75,8 @@ static int pty_stamped_utmp = 0;
static int pty_child_pid; static int pty_child_pid;
static int pty_utmp_helper_pid, pty_utmp_helper_pipe; static int pty_utmp_helper_pid, pty_utmp_helper_pipe;
static int pty_term_width, pty_term_height; static int pty_term_width, pty_term_height;
static sig_atomic_t pty_child_dead; static volatile sig_atomic_t pty_child_dead;
static int pty_exit_code; static volatile int pty_exit_code;
#ifndef OMIT_UTMP #ifndef OMIT_UTMP
static struct utmp utmp_entry; static struct utmp utmp_entry;
#endif #endif
@ -163,18 +164,21 @@ static void cleanup_utmp(void)
static void sigchld_handler(int signum) static void sigchld_handler(int signum)
{ {
int save_errno = errno;
pid_t pid; pid_t pid;
int status; int status;
pid = waitpid(-1, &status, WNOHANG); pid = waitpid(-1, &status, WNOHANG);
if (pid == pty_child_pid && (WIFEXITED(status) || WIFSIGNALED(status))) { if (pid == pty_child_pid && (WIFEXITED(status) || WIFSIGNALED(status))) {
pty_exit_code = status; pty_exit_code = status;
pty_child_dead = TRUE; pty_child_dead = TRUE;
} }
errno = save_errno;
} }
static void fatal_sig_handler(int signum) static void fatal_sig_handler(int signum)
{ {
signal(signum, SIG_DFL); putty_signal(signum, SIG_DFL);
cleanup_utmp(); cleanup_utmp();
setuid(getuid()); setuid(getuid());
raise(signum); raise(signum);
@ -254,6 +258,9 @@ void pty_pre_init(void)
pid_t pid; pid_t pid;
int pipefd[2]; 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; pty_master_fd = -1;
if (geteuid() != getuid() || getegid() != getgid()) { if (geteuid() != getuid() || getegid() != getgid()) {
@ -289,7 +296,7 @@ void pty_pre_init(void)
ret = read(pipefd[0], buffer, lenof(buffer)); ret = read(pipefd[0], buffer, lenof(buffer));
if (ret <= 0) { if (ret <= 0) {
cleanup_utmp(); cleanup_utmp();
exit(0); _exit(0);
} else if (!pty_stamped_utmp) { } else if (!pty_stamped_utmp) {
if (dlen < lenof(display)) if (dlen < lenof(display))
memcpy(display+dlen, buffer, memcpy(display+dlen, buffer,
@ -307,47 +314,45 @@ void pty_pre_init(void)
* unfortunately unprotected against SIGKILL, * unfortunately unprotected against SIGKILL,
* but that's life. * but that's life.
*/ */
signal(SIGHUP, fatal_sig_handler); putty_signal(SIGHUP, fatal_sig_handler);
signal(SIGINT, fatal_sig_handler); putty_signal(SIGINT, fatal_sig_handler);
signal(SIGQUIT, fatal_sig_handler); putty_signal(SIGQUIT, fatal_sig_handler);
signal(SIGILL, fatal_sig_handler); putty_signal(SIGILL, fatal_sig_handler);
signal(SIGABRT, fatal_sig_handler); putty_signal(SIGABRT, fatal_sig_handler);
signal(SIGFPE, fatal_sig_handler); putty_signal(SIGFPE, fatal_sig_handler);
signal(SIGPIPE, fatal_sig_handler); putty_signal(SIGPIPE, fatal_sig_handler);
signal(SIGALRM, fatal_sig_handler); putty_signal(SIGALRM, fatal_sig_handler);
signal(SIGTERM, fatal_sig_handler); putty_signal(SIGTERM, fatal_sig_handler);
signal(SIGSEGV, fatal_sig_handler); putty_signal(SIGSEGV, fatal_sig_handler);
signal(SIGUSR1, fatal_sig_handler); putty_signal(SIGUSR1, fatal_sig_handler);
signal(SIGUSR2, fatal_sig_handler); putty_signal(SIGUSR2, fatal_sig_handler);
#ifdef SIGBUS #ifdef SIGBUS
signal(SIGBUS, fatal_sig_handler); putty_signal(SIGBUS, fatal_sig_handler);
#endif #endif
#ifdef SIGPOLL #ifdef SIGPOLL
signal(SIGPOLL, fatal_sig_handler); putty_signal(SIGPOLL, fatal_sig_handler);
#endif #endif
#ifdef SIGPROF #ifdef SIGPROF
signal(SIGPROF, fatal_sig_handler); putty_signal(SIGPROF, fatal_sig_handler);
#endif #endif
#ifdef SIGSYS #ifdef SIGSYS
signal(SIGSYS, fatal_sig_handler); putty_signal(SIGSYS, fatal_sig_handler);
#endif #endif
#ifdef SIGTRAP #ifdef SIGTRAP
signal(SIGTRAP, fatal_sig_handler); putty_signal(SIGTRAP, fatal_sig_handler);
#endif #endif
#ifdef SIGVTALRM #ifdef SIGVTALRM
signal(SIGVTALRM, fatal_sig_handler); putty_signal(SIGVTALRM, fatal_sig_handler);
#endif #endif
#ifdef SIGXCPU #ifdef SIGXCPU
signal(SIGXCPU, fatal_sig_handler); putty_signal(SIGXCPU, fatal_sig_handler);
#endif #endif
#ifdef SIGXFSZ #ifdef SIGXFSZ
signal(SIGXFSZ, fatal_sig_handler); putty_signal(SIGXFSZ, fatal_sig_handler);
#endif #endif
#ifdef SIGIO #ifdef SIGIO
signal(SIGIO, fatal_sig_handler); putty_signal(SIGIO, fatal_sig_handler);
#endif #endif
/* Also clean up utmp on normal exit. */
atexit(cleanup_utmp);
setup_utmp(pty_name, display); setup_utmp(pty_name, display);
} }
} }
@ -356,7 +361,6 @@ void pty_pre_init(void)
close(pipefd[0]); close(pipefd[0]);
pty_utmp_helper_pid = pid; pty_utmp_helper_pid = pid;
pty_utmp_helper_pipe = pipefd[1]; pty_utmp_helper_pipe = pipefd[1];
signal(SIGCHLD, sigchld_handler);
} }
#endif #endif
@ -447,7 +451,7 @@ static char *pty_init(void *frontend, void **backend_handle,
slavefd = open(pty_name, O_RDWR); slavefd = open(pty_name, O_RDWR);
if (slavefd < 0) { if (slavefd < 0) {
perror("slave pty: open"); perror("slave pty: open");
exit(1); _exit(1);
} }
close(pty_master_fd); 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 * parent, particularly by things like sh -c 'pterm &' and
* some window managers. Reverse this for our child process. * some window managers. Reverse this for our child process.
*/ */
signal(SIGINT, SIG_DFL); putty_signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL); putty_signal(SIGQUIT, SIG_DFL);
if (pty_argv) if (pty_argv)
execvp(pty_argv[0], pty_argv); execvp(pty_argv[0], pty_argv);
else { else {
@ -496,12 +500,10 @@ static char *pty_init(void *frontend, void **backend_handle,
* If we're here, exec has gone badly foom. * If we're here, exec has gone badly foom.
*/ */
perror("exec"); perror("exec");
exit(127); _exit(127);
} else { } else {
close(slavefd);
pty_child_pid = pid; pty_child_pid = pid;
pty_child_dead = FALSE; pty_child_dead = FALSE;
signal(SIGCHLD, sigchld_handler);
} }
return NULL; return NULL;

31
unix/signal.c Normal file
View File

@ -0,0 +1,31 @@
#include <signal.h>
/*
* 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:
*/

View File

@ -50,4 +50,7 @@ int next_socket(int *state, int *rwx);
#define strnicmp strncasecmp #define strnicmp strncasecmp
#define stricmp strcasecmp #define stricmp strcasecmp
/* BSD-semantics version of signal() */
void (*putty_signal(int sig, void (*func)(int)))(int);
#endif #endif