#define _XOPEN_SOURCE
#define _XOPEN_SOURCE_EXTENDED
#define _GNU_SOURCE
-#include <features.h>
#include <stdio.h>
#include <stdlib.h>
#include <pwd.h>
#include <time.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <errno.h>
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));
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);
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);
#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);
setuid(getuid());
raise(signum);
}
+#endif
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. */
/* 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);
#endif
from_backend(pty_frontend, 0, message, strlen(message));
}
+
+ notify_remote_exit(pty_frontend);
}
return !finished;
}
* 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;
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) {
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);
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);
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 {
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.
*/
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
}
/*