1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-25 01:02:24 +00:00

Unix Pageant: -T option, tying lifetime to controlling tty.

This is intended to be a useful mode when you want to run an ssh agent
in a terminal session with no X11 available. You just execute a
command along the lines of eval $(pageant -T), and then Pageant will
run in the background for the rest of that terminal session - and when
the terminal session ends, so that Pageant loses its controlling tty,
it will take that as the signal to shut down. So, no need to manually
kill it, and unlike 'pageant --exec $SHELL', you can also do this half
way through a session if you don't realise until later that you need
an SSH agent, without losing any shell command history or other shell
context that you've accumulated so far in the session.

Unfortunately, I haven't been able to find any reliable way to
actually implement this -T mode, short of having Pageant wake up at
regular intervals and try to open /dev/tty to see if it's still there.
I had hoped that I could arrange to reliably get SIGHUP, or select on
/dev/tty for exceptional conditions, or some such, but nothing I've
tried along those lines seems to work.
This commit is contained in:
Simon Tatham 2015-05-08 19:50:48 +01:00
parent cc420507a9
commit c59c6a8db9

View File

@ -10,6 +10,7 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#define PUTTY_DO_GLOBALS /* actually _define_ globals */
@ -180,7 +181,7 @@ void pageant_print_env(int pid)
socketname, (int)pid);
}
void pageant_fork_and_print_env(void)
void pageant_fork_and_print_env(int retain_tty)
{
pid_t pid = fork();
if (pid == -1) {
@ -211,7 +212,16 @@ void pageant_fork_and_print_env(void)
}
close(0);
close(1);
setsid();
if (retain_tty) {
/* Get out of our previous process group, to avoid being
* blasted by passing signals. But keep our controlling tty,
* so we can keep checking to see if we still have one. */
setpgrp();
} else {
/* Do that, but also leave our entire session and detach from
* the controlling tty (if any). */
setsid();
}
}
int signalpipe[2];
@ -222,6 +232,13 @@ void sigchld(int signum)
/* not much we can do about it */;
}
#define TTY_LIFE_POLL_INTERVAL (TICKSPERSEC * 30)
void *dummy_timer_ctx;
static void tty_life_timer(void *ctx, unsigned long now)
{
schedule_timer(TTY_LIFE_POLL_INTERVAL, tty_life_timer, &dummy_timer_ctx);
}
int main(int argc, char **argv)
{
int *fdlist;
@ -234,7 +251,7 @@ int main(int argc, char **argv)
struct pageant_listen_state *pl;
Socket sock;
enum {
LIFE_UNSPEC, LIFE_X11, LIFE_DEBUG, LIFE_PERM, LIFE_EXEC
LIFE_UNSPEC, LIFE_X11, LIFE_TTY, LIFE_DEBUG, LIFE_PERM, LIFE_EXEC
} life = LIFE_UNSPEC;
const char *display = NULL;
int doing_opts = TRUE;
@ -261,6 +278,8 @@ int main(int argc, char **argv)
pageant_logfp = stderr;
} else if (!strcmp(p, "-X")) {
life = LIFE_X11;
} else if (!strcmp(p, "-T")) {
life = LIFE_TTY;
} else if (!strcmp(p, "--debug")) {
life = LIFE_DEBUG;
} else if (!strcmp(p, "--permanent")) {
@ -370,9 +389,13 @@ int main(int argc, char **argv)
smemclr(greeting, greetinglen);
sfree(greeting);
pageant_fork_and_print_env();
pageant_fork_and_print_env(FALSE);
} else if (life == LIFE_TTY) {
schedule_timer(TTY_LIFE_POLL_INTERVAL,
tty_life_timer, &dummy_timer_ctx);
pageant_fork_and_print_env(TRUE);
} else if (life == LIFE_PERM) {
pageant_fork_and_print_env();
pageant_fork_and_print_env(FALSE);
} else if (life == LIFE_DEBUG) {
pageant_print_env(getpid());
pageant_logfp = stdout;
@ -491,6 +514,27 @@ int main(int argc, char **argv)
exit(1);
}
if (life == LIFE_TTY) {
/*
* Every time we wake up (whether it was due to tty_timer
* elapsing or for any other reason), poll to see if we
* still have a controlling terminal. If we don't, then
* our containing tty session has ended, so it's time to
* clean up and leave.
*/
int fd = open("/dev/tty", O_RDONLY);
if (fd < 0) {
if (errno != ENXIO) {
perror("/dev/tty: open");
exit(1);
}
time_to_die = TRUE;
break;
} else {
close(fd);
}
}
for (i = 0; i < fdcount; i++) {
fd = fdlist[i];
/*