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:
parent
406bc897b3
commit
93e9fadc75
2
Recipe
2
Recipe
@ -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
|
||||||
|
19
unix/pterm.c
19
unix/pterm.c
@ -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;
|
||||||
|
70
unix/pty.c
70
unix/pty.c
@ -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
31
unix/signal.c
Normal 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:
|
||||||
|
*/
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user