X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/125105d16c788398562ac03e91ce7a0dc0292492..f89c329410c18fe1f09d843747fad77babb9f89c:/unix/pty.c diff --git a/unix/pty.c b/unix/pty.c index dac67364..d99d4e50 100644 --- a/unix/pty.c +++ b/unix/pty.c @@ -14,7 +14,6 @@ #define _XOPEN_SOURCE #define _XOPEN_SOURCE_EXTENDED #define _GNU_SOURCE -#include #include #include @@ -28,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -74,29 +74,29 @@ static int pty_master_fd; static void *pty_frontend; static char pty_name[FILENAME_MAX]; static int pty_signal_pipe[2]; -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 int pty_child_dead, pty_finished; static int pty_exit_code; -#ifndef OMIT_UTMP -static struct utmp utmp_entry; -#endif char **pty_argv; int use_pty_argv = TRUE; static void pty_close(void); +#ifndef OMIT_UTMP +static int pty_utmp_helper_pid, pty_utmp_helper_pipe; +static int pty_stamped_utmp = 0; +static struct utmp utmp_entry; + static void setup_utmp(char *ttyname, char *location) { -#ifndef OMIT_UTMP #ifdef HAVE_LASTLOG struct lastlog lastlog_entry; FILE *lastlog; #endif struct passwd *pw; FILE *wtmp; + time_t uttime; pw = getpwuid(getuid()); memset(&utmp_entry, 0, sizeof(utmp_entry)); @@ -106,7 +106,10 @@ static void setup_utmp(char *ttyname, char *location) strncpy(utmp_entry.ut_id, ttyname+8, lenof(utmp_entry.ut_id)); strncpy(utmp_entry.ut_user, pw->pw_name, lenof(utmp_entry.ut_user)); strncpy(utmp_entry.ut_host, location, lenof(utmp_entry.ut_host)); - time(&utmp_entry.ut_time); + /* Apparently there are some architectures where (struct utmp).ut_time + * is not essentially time_t (e.g. Linux amd64). Hence the temporary. */ + time(&uttime); + utmp_entry.ut_time = uttime; /* may truncate */ #if defined HAVE_PUTUTLINE utmpname(UTMP_FILE); @@ -134,20 +137,20 @@ static void setup_utmp(char *ttyname, char *location) pty_stamped_utmp = 1; -#endif } static void cleanup_utmp(void) { -#ifndef OMIT_UTMP FILE *wtmp; + time_t uttime; if (!pty_stamped_utmp) return; utmp_entry.ut_type = DEAD_PROCESS; memset(utmp_entry.ut_user, 0, lenof(utmp_entry.ut_user)); - time(&utmp_entry.ut_time); + time(&uttime); + utmp_entry.ut_time = uttime; if ((wtmp = fopen(WTMP_FILE, "a")) != NULL) { fwrite(&utmp_entry, 1, sizeof(utmp_entry), wtmp); @@ -165,14 +168,15 @@ static void cleanup_utmp(void) #endif pty_stamped_utmp = 0; /* ensure we never double-cleanup */ -#endif } +#endif static void sigchld_handler(int signum) { write(pty_signal_pipe[1], "x", 1); } +#ifndef OMIT_UTMP static void fatal_sig_handler(int signum) { putty_signal(signum, SIG_DFL); @@ -180,6 +184,7 @@ static void fatal_sig_handler(int signum) setuid(getuid()); raise(signum); } +#endif static void pty_open_master(void) { @@ -252,8 +257,10 @@ static void pty_open_master(void) */ void pty_pre_init(void) { +#ifndef OMIT_UTMP pid_t pid; int pipefd[2]; +#endif /* set the child signal handler straight away; it needs to be set * before we ever fork. */ @@ -363,8 +370,8 @@ void pty_pre_init(void) /* Drop privs. */ { - int gid = getgid(), uid = getuid(); #ifndef HAVE_NO_SETRESUID + int gid = getgid(), uid = getuid(); int setresgid(gid_t, gid_t, gid_t); int setresuid(uid_t, uid_t, uid_t); setresgid(gid, gid, gid); @@ -467,6 +474,8 @@ int pty_select_result(int fd, int event) #endif from_backend(pty_frontend, 0, message, strlen(message)); } + + notify_remote_exit(pty_frontend); } return !finished; } @@ -485,8 +494,9 @@ static void pty_uxsel_setup(void) * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static char *pty_init(void *frontend, void **backend_handle, Config *cfg, - char *host, int port, char **realhost, int nodelay) +static const char *pty_init(void *frontend, void **backend_handle, Config *cfg, + char *host, int port, char **realhost, int nodelay, + int keepalive) { int slavefd; pid_t pid, pgrp; @@ -513,13 +523,15 @@ static char *pty_init(void *frontend, void **backend_handle, Config *cfg, tcsetattr(pty_master_fd, TCSANOW, &attrs); } +#ifndef OMIT_UTMP /* * Stamp utmp (that is, tell the utmp helper process to do so), * or not. */ - if (!cfg->stamp_utmp) + if (!cfg->stamp_utmp) { close(pty_utmp_helper_pipe); /* just let the child process die */ - else { + pty_utmp_helper_pipe = -1; + } else { char *location = get_x_display(pty_frontend); int len = strlen(location)+1, pos = 0; /* +1 to include NUL */ while (pos < len) { @@ -527,11 +539,13 @@ static char *pty_init(void *frontend, void **backend_handle, Config *cfg, if (ret < 0) { perror("pterm: writing to utmp helper process"); close(pty_utmp_helper_pipe); /* arrgh, just give up */ + pty_utmp_helper_pipe = -1; break; } pos += ret; } } +#endif windowid = get_windowid(pty_frontend); @@ -565,9 +579,9 @@ static char *pty_init(void *frontend, void **backend_handle, Config *cfg, ioctl(slavefd, TIOCSCTTY, 1); pgrp = getpid(); tcsetpgrp(slavefd, pgrp); - setpgrp(); + setpgid(pgrp, pgrp); close(open(pty_name, O_WRONLY, 0)); - setpgrp(); + setpgid(pgrp, pgrp); /* Close everything _else_, for tidiness. */ for (i = 3; i < 1024; i++) close(i); @@ -581,13 +595,39 @@ static char *pty_init(void *frontend, void **backend_handle, Config *cfg, sprintf(windowid_env_var, "WINDOWID=%ld", windowid); putenv(windowid_env_var); } + { + char *e = cfg->environmt; + char *var, *varend, *val, *varval; + while (*e) { + var = e; + while (*e && *e != '\t') e++; + varend = e; + if (*e == '\t') e++; + val = e; + while (*e) e++; + e++; + + varval = dupprintf("%.*s=%s", varend-var, var, val); + putenv(varval); + /* + * We must not free varval, since putenv links it + * into the environment _in place_. Weird, but + * there we go. Memory usage will be rationalised + * as soon as we exec anyway. + */ + } + } + /* * SIGINT and SIGQUIT may have been set to ignored by our * parent, particularly by things like sh -c 'pterm &' and - * some window managers. Reverse this for our child process. + * some window managers. SIGCHLD, meanwhile, was blocked + * during pt_main() startup. Reverse all this for our child + * process. */ putty_signal(SIGINT, SIG_DFL); putty_signal(SIGQUIT, SIG_DFL); + block_signal(SIGCHLD, 0); if (pty_argv) execvp(pty_argv[0], pty_argv); else { @@ -623,21 +663,23 @@ static char *pty_init(void *frontend, void **backend_handle, Config *cfg, return NULL; } -/* - * Stub routine (we don't have any need to reconfigure this backend). - */ static void pty_reconfig(void *handle, Config *cfg) { + /* + * We don't have much need to reconfigure this backend, but + * unfortunately we do need to pick up the setting of Close On + * Exit so we know whether to give a `terminated' message. + */ + pty_cfg = *cfg; /* structure copy */ } /* - * Stub routine (never called in pterm + * Stub routine (never called in pterm). */ static void pty_free(void *handle) { } - /* * Called to send data down the pty. */ @@ -664,7 +706,12 @@ static void pty_close(void) close(pty_master_fd); pty_master_fd = -1; } - close(pty_utmp_helper_pipe); /* this causes utmp to be cleaned up */ +#ifndef OMIT_UTMP + if (pty_utmp_helper_pipe >= 0) { + close(pty_utmp_helper_pipe); /* this causes utmp to be cleaned up */ + pty_utmp_helper_pipe = -1; + } +#endif } /* @@ -757,6 +804,11 @@ static int pty_exitcode(void *handle) return pty_exit_code; } +static int pty_cfg_info(void *handle) +{ + return 0; +} + Backend pty_backend = { pty_init, pty_free, @@ -773,5 +825,6 @@ Backend pty_backend = { pty_provide_ldisc, pty_provide_logctx, pty_unthrottle, + pty_cfg_info, 1 };