*/
char **pty_argv;
+char *pty_osx_envrestore_prefix;
+
static void pty_close(Pty pty);
static void pty_try_write(Pty pty);
}
#endif
+#ifndef NO_PTY_PRE_INIT
static void sigchld_handler(int signum)
{
if (write(pty_signal_pipe[1], "x", 1) <= 0)
/* not much we can do about it */;
}
+#endif
#ifndef OMIT_UTMP
static void fatal_sig_handler(int signum)
{
putty_signal(signum, SIG_DFL);
cleanup_utmp();
- setuid(getuid());
raise(signum);
}
#endif
;
#ifdef HAVE_POSIX_OPENPT
+#ifdef SET_NONBLOCK_VIA_OPENPT
+ /*
+ * OS X, as of 10.10 at least, doesn't permit me to set O_NONBLOCK
+ * on pty master fds via the usual fcntl mechanism. Fortunately,
+ * it does let me work around this by adding O_NONBLOCK to the
+ * posix_openpt flags parameter, which isn't a documented use of
+ * the API but seems to work. So we'll do that for now.
+ */
+ pty->master_fd = posix_openpt(flags | O_NONBLOCK);
+#else
pty->master_fd = posix_openpt(flags);
+#endif
if (pty->master_fd < 0) {
perror("posix_openpt");
strncpy(pty->name, ptsname(pty->master_fd), FILENAME_MAX-1);
#endif
- {
- /*
- * Set the pty master into non-blocking mode.
- */
- int fl;
- fl = fcntl(pty->master_fd, F_GETFL);
- if (fl != -1 && !(fl & O_NONBLOCK))
- fcntl(pty->master_fd, F_SETFL, fl | O_NONBLOCK);
- }
+#ifndef SET_NONBLOCK_VIA_OPENPT
+ nonblock(pty->master_fd);
+#endif
if (!ptys_by_fd)
ptys_by_fd = newtree234(pty_compare_by_fd);
add234(ptys_by_fd, pty);
}
+static Pty new_pty_struct(void)
+{
+ Pty pty = snew(struct pty_tag);
+ pty->conf = NULL;
+ bufchain_init(&pty->output_data);
+ return pty;
+}
+
/*
* Pre-initialisation. This is here to get around the fact that GTK
* doesn't like being run in setuid/setgid programs (probably
*/
void pty_pre_init(void)
{
+#ifndef NO_PTY_PRE_INIT
+
Pty pty;
#ifndef OMIT_UTMP
int pipefd[2];
#endif
- pty = single_pty = snew(struct pty_tag);
- bufchain_init(&pty->output_data);
+ pty = single_pty = new_pty_struct();
/* set the child signal handler straight away; it needs to be set
* before we ever fork. */
}
#endif
}
+
+#endif /* NO_PTY_PRE_INIT */
+
}
int pty_real_select_result(Pty pty, int event, int status)
if (close_on_exit == FORCE_OFF ||
(close_on_exit == AUTO && pty->exit_code != 0)) {
char message[512];
+ message[0] = '\0';
if (WIFEXITED(pty->exit_code))
sprintf(message, "\r\n[pterm: process terminated with exit"
" code %d]\r\n", WEXITSTATUS(pty->exit_code));
* freed by the caller.
*/
static const char *pty_init(void *frontend, void **backend_handle, Conf *conf,
- char *host, int port, char **realhost, int nodelay,
- int keepalive)
+ const char *host, int port, char **realhost,
+ int nodelay, int keepalive)
{
int slavefd;
pid_t pid, pgrp;
if (single_pty) {
pty = single_pty;
+ assert(pty->conf == NULL);
} else {
- pty = snew(struct pty_tag);
+ pty = new_pty_struct();
pty->master_fd = pty->slave_fd = -1;
#ifndef OMIT_UTMP
pty_stamped_utmp = FALSE;
if (pty->master_fd < 0)
pty_open_master(pty);
- /*
- * Set the backspace character to be whichever of ^H and ^? is
- * specified by bksp_is_delete.
- */
- {
- struct termios attrs;
- tcgetattr(pty->master_fd, &attrs);
- attrs.c_cc[VERASE] = conf_get_int(conf, CONF_bksp_is_delete)
- ? '\177' : '\010';
- tcsetattr(pty->master_fd, TCSANOW, &attrs);
- }
-
#ifndef OMIT_UTMP
/*
* Stamp utmp (that is, tell the utmp helper process to do so),
close(pty_utmp_helper_pipe); /* just let the child process die */
pty_utmp_helper_pipe = -1;
} else {
- char *location = get_x_display(pty->frontend);
+ const char *location = get_x_display(pty->frontend);
int len = strlen(location)+1, pos = 0; /* +1 to include NUL */
while (pos < len) {
int ret = write(pty_utmp_helper_pipe, location+pos, len - pos);
}
if (pid == 0) {
+ struct termios attrs;
+
/*
* We are the child.
*/
+ if (pty_osx_envrestore_prefix) {
+ int plen = strlen(pty_osx_envrestore_prefix);
+ extern char **environ;
+ char **ep;
+
+ restart_osx_env_restore:
+ for (ep = environ; *ep; ep++) {
+ char *e = *ep;
+
+ if (!strncmp(e, pty_osx_envrestore_prefix, plen)) {
+ int unset = (e[plen] == 'u');
+ char *pname = dupprintf("%.*s", (int)strcspn(e, "="), e);
+ char *name = pname + plen + 1;
+ char *value = e + strcspn(e, "=");
+ if (*value) value++;
+ value = dupstr(value);
+ if (unset)
+ unsetenv(name);
+ else
+ setenv(name, value, 1);
+ unsetenv(pname);
+ sfree(pname);
+ sfree(value);
+ goto restart_osx_env_restore;
+ }
+ }
+ }
+
slavefd = pty_open_slave(pty);
if (slavefd < 0) {
perror("slave pty: open");
}
close(pty->master_fd);
- fcntl(slavefd, F_SETFD, 0); /* don't close on exec */
+ noncloexec(slavefd);
dup2(slavefd, 0);
dup2(slavefd, 1);
dup2(slavefd, 2);
#endif
pgrp = getpid();
tcsetpgrp(0, pgrp);
+
+ /*
+ * Set up configuration-dependent termios settings on the new
+ * pty. Linux would have let us do this on the pty master
+ * before we forked, but that fails on OS X, so we do it here
+ * instead.
+ */
+ if (tcgetattr(0, &attrs) == 0) {
+ /*
+ * Set the backspace character to be whichever of ^H and
+ * ^? is specified by bksp_is_delete.
+ */
+ attrs.c_cc[VERASE] = conf_get_int(conf, CONF_bksp_is_delete)
+ ? '\177' : '\010';
+
+ /*
+ * Set the IUTF8 bit iff the character set is UTF-8.
+ */
+#ifdef IUTF8
+ if (frontend_is_utf8(frontend))
+ attrs.c_iflag |= IUTF8;
+ else
+ attrs.c_iflag &= ~IUTF8;
+#endif
+
+ tcsetattr(0, TCSANOW, &attrs);
+ }
+
setpgid(pgrp, pgrp);
- close(open(pty->name, O_WRONLY, 0));
+ {
+ int ptyfd = open(pty->name, O_WRONLY, 0);
+ if (ptyfd >= 0)
+ close(ptyfd);
+ }
setpgid(pgrp, pgrp);
{
char *term_env_var = dupprintf("TERM=%s",
* environment in place.
*/
}
+ {
+ /*
+ * In case we were invoked with a --display argument that
+ * doesn't match DISPLAY in our actual environment, we
+ * should set DISPLAY for processes running inside the
+ * terminal to match the display the terminal itself is
+ * on.
+ */
+ const char *x_display = get_x_display(pty->frontend);
+ char *x_display_env_var = dupprintf("DISPLAY=%s", x_display);
+ putenv(x_display_env_var);
+ /* As above, we don't free this. */
+ }
#endif
{
char *key, *val;
/*
* SIGINT, SIGQUIT and SIGPIPE may have been set to ignored by
* our parent, particularly by things like sh -c 'pterm &' and
- * some window or session managers. SIGCHLD, meanwhile, was
- * blocked during pt_main() startup. Reverse all this for our
- * child process.
+ * some window or session managers. SIGPIPE was also
+ * (potentially) blocked by us during startup. Reverse all
+ * this for our child process.
*/
putty_signal(SIGINT, SIG_DFL);
putty_signal(SIGQUIT, SIG_DFL);
putty_signal(SIGPIPE, SIG_DFL);
- block_signal(SIGCHLD, 0);
+ block_signal(SIGPIPE, 0);
if (pty_argv) {
/*
* Exec the exact argument list we were given.
*backend_handle = pty;
- *realhost = dupprintf("\0");
+ *realhost = dupstr("");
return NULL;
}
del234(ptys_by_pid, pty);
del234(ptys_by_fd, pty);
- sfree(pty);
+ bufchain_clear(&pty->output_data);
+
+ conf_free(pty->conf);
+ pty->conf = NULL;
+
+ if (pty == single_pty) {
+ /*
+ * Leave this structure around in case we need to Restart
+ * Session.
+ */
+ } else {
+ sfree(pty);
+ }
}
static void pty_try_write(Pty pty)
/*
* Called to send data down the pty.
*/
-static int pty_send(void *handle, char *buf, int len)
+static int pty_send(void *handle, const char *buf, int len)
{
Pty pty = (Pty)handle;
pty_provide_logctx,
pty_unthrottle,
pty_cfg_info,
+ NULL /* test_for_upstream */,
"pty",
-1,
0