OSDN Git Service

Delete unused source files for 1.98d.
[ffftp/ffftp.git] / contrib / putty / UNIX / UXPTY.C
diff --git a/contrib/putty/UNIX/UXPTY.C b/contrib/putty/UNIX/UXPTY.C
deleted file mode 100644 (file)
index b1e240e..0000000
+++ /dev/null
@@ -1,1096 +0,0 @@
-/*\r
- * Pseudo-tty backend for pterm.\r
- */\r
-\r
-#define _GNU_SOURCE\r
-\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#include <unistd.h>\r
-#include <signal.h>\r
-#include <assert.h>\r
-#include <fcntl.h>\r
-#include <termios.h>\r
-#include <grp.h>\r
-#include <utmp.h>\r
-#include <pwd.h>\r
-#include <time.h>\r
-#include <sys/types.h>\r
-#include <sys/stat.h>\r
-#include <sys/wait.h>\r
-#include <sys/ioctl.h>\r
-#include <errno.h>\r
-\r
-#include "putty.h"\r
-#include "tree234.h"\r
-\r
-#ifndef OMIT_UTMP\r
-#include <utmpx.h>\r
-#endif\r
-\r
-#ifndef FALSE\r
-#define FALSE 0\r
-#endif\r
-#ifndef TRUE\r
-#define TRUE 1\r
-#endif\r
-\r
-/* updwtmpx() needs the name of the wtmp file.  Try to find it. */\r
-#ifndef WTMPX_FILE\r
-#ifdef _PATH_WTMPX\r
-#define WTMPX_FILE _PATH_WTMPX\r
-#else\r
-#define WTMPX_FILE "/var/log/wtmpx"\r
-#endif\r
-#endif\r
-\r
-#ifndef LASTLOG_FILE\r
-#ifdef _PATH_LASTLOG\r
-#define LASTLOG_FILE _PATH_LASTLOG\r
-#else\r
-#define LASTLOG_FILE "/var/log/lastlog"\r
-#endif\r
-#endif\r
-\r
-/*\r
- * Set up a default for vaguely sane systems. The idea is that if\r
- * OMIT_UTMP is not defined, then at least one of the symbols which\r
- * enable particular forms of utmp processing should be, if only so\r
- * that a link error can warn you that you should have defined\r
- * OMIT_UTMP if you didn't want any. Currently HAVE_PUTUTLINE is\r
- * the only such symbol.\r
- */\r
-#ifndef OMIT_UTMP\r
-#if !defined HAVE_PUTUTLINE\r
-#define HAVE_PUTUTLINE\r
-#endif\r
-#endif\r
-\r
-typedef struct pty_tag *Pty;\r
-\r
-/*\r
- * The pty_signal_pipe, along with the SIGCHLD handler, must be\r
- * process-global rather than session-specific.\r
- */\r
-static int pty_signal_pipe[2] = { -1, -1 };   /* obviously bogus initial val */\r
-\r
-struct pty_tag {\r
-    Config cfg;\r
-    int master_fd, slave_fd;\r
-    void *frontend;\r
-    char name[FILENAME_MAX];\r
-    pid_t child_pid;\r
-    int term_width, term_height;\r
-    int child_dead, finished;\r
-    int exit_code;\r
-    bufchain output_data;\r
-};\r
-\r
-/*\r
- * We store our pty backends in a tree sorted by master fd, so that\r
- * when we get an uxsel notification we know which backend instance\r
- * is the owner of the pty that caused it.\r
- */\r
-static int pty_compare_by_fd(void *av, void *bv)\r
-{\r
-    Pty a = (Pty)av;\r
-    Pty b = (Pty)bv;\r
-\r
-    if (a->master_fd < b->master_fd)\r
-       return -1;\r
-    else if (a->master_fd > b->master_fd)\r
-       return +1;\r
-    return 0;\r
-}\r
-\r
-static int pty_find_by_fd(void *av, void *bv)\r
-{\r
-    int a = *(int *)av;\r
-    Pty b = (Pty)bv;\r
-\r
-    if (a < b->master_fd)\r
-       return -1;\r
-    else if (a > b->master_fd)\r
-       return +1;\r
-    return 0;\r
-}\r
-\r
-static tree234 *ptys_by_fd = NULL;\r
-\r
-/*\r
- * We also have a tree sorted by child pid, so that when we wait()\r
- * in response to the signal we know which backend instance is the\r
- * owner of the process that caused the signal.\r
- */\r
-static int pty_compare_by_pid(void *av, void *bv)\r
-{\r
-    Pty a = (Pty)av;\r
-    Pty b = (Pty)bv;\r
-\r
-    if (a->child_pid < b->child_pid)\r
-       return -1;\r
-    else if (a->child_pid > b->child_pid)\r
-       return +1;\r
-    return 0;\r
-}\r
-\r
-static int pty_find_by_pid(void *av, void *bv)\r
-{\r
-    pid_t a = *(pid_t *)av;\r
-    Pty b = (Pty)bv;\r
-\r
-    if (a < b->child_pid)\r
-       return -1;\r
-    else if (a > b->child_pid)\r
-       return +1;\r
-    return 0;\r
-}\r
-\r
-static tree234 *ptys_by_pid = NULL;\r
-\r
-/*\r
- * If we are using pty_pre_init(), it will need to have already\r
- * allocated a pty structure, which we must then return from\r
- * pty_init() rather than allocating a new one. Here we store that\r
- * structure between allocation and use.\r
- * \r
- * Note that although most of this module is entirely capable of\r
- * handling multiple ptys in a single process, pty_pre_init() is\r
- * fundamentally _dependent_ on there being at most one pty per\r
- * process, so the normal static-data constraints don't apply.\r
- * \r
- * Likewise, since utmp is only used via pty_pre_init, it too must\r
- * be single-instance, so we can declare utmp-related variables\r
- * here.\r
- */\r
-static Pty single_pty = NULL;\r
-\r
-#ifndef OMIT_UTMP\r
-static pid_t pty_utmp_helper_pid;\r
-static int pty_utmp_helper_pipe;\r
-static int pty_stamped_utmp;\r
-static struct utmpx utmp_entry;\r
-#endif\r
-\r
-/*\r
- * pty_argv is a grievous hack to allow a proper argv to be passed\r
- * through from the Unix command line. Again, it doesn't really\r
- * make sense outside a one-pty-per-process setup.\r
- */\r
-char **pty_argv;\r
-\r
-static void pty_close(Pty pty);\r
-static void pty_try_write(Pty pty);\r
-\r
-#ifndef OMIT_UTMP\r
-static void setup_utmp(char *ttyname, char *location)\r
-{\r
-#ifdef HAVE_LASTLOG\r
-    struct lastlog lastlog_entry;\r
-    FILE *lastlog;\r
-#endif\r
-    struct passwd *pw;\r
-    struct timeval tv;\r
-\r
-    pw = getpwuid(getuid());\r
-    memset(&utmp_entry, 0, sizeof(utmp_entry));\r
-    utmp_entry.ut_type = USER_PROCESS;\r
-    utmp_entry.ut_pid = getpid();\r
-    strncpy(utmp_entry.ut_line, ttyname+5, lenof(utmp_entry.ut_line));\r
-    strncpy(utmp_entry.ut_id, ttyname+8, lenof(utmp_entry.ut_id));\r
-    strncpy(utmp_entry.ut_user, pw->pw_name, lenof(utmp_entry.ut_user));\r
-    strncpy(utmp_entry.ut_host, location, lenof(utmp_entry.ut_host));\r
-    /*\r
-     * Apparently there are some architectures where (struct\r
-     * utmpx).ut_tv is not essentially struct timeval (e.g. Linux\r
-     * amd64). Hence the temporary.\r
-     */\r
-    gettimeofday(&tv, NULL);\r
-    utmp_entry.ut_tv.tv_sec = tv.tv_sec;\r
-    utmp_entry.ut_tv.tv_usec = tv.tv_usec;\r
-\r
-    setutxent();\r
-    pututxline(&utmp_entry);\r
-    endutxent();\r
-\r
-    updwtmpx(WTMPX_FILE, &utmp_entry);\r
-\r
-#ifdef HAVE_LASTLOG\r
-    memset(&lastlog_entry, 0, sizeof(lastlog_entry));\r
-    strncpy(lastlog_entry.ll_line, ttyname+5, lenof(lastlog_entry.ll_line));\r
-    strncpy(lastlog_entry.ll_host, location, lenof(lastlog_entry.ll_host));\r
-    time(&lastlog_entry.ll_time);\r
-    if ((lastlog = fopen(LASTLOG_FILE, "r+")) != NULL) {\r
-       fseek(lastlog, sizeof(lastlog_entry) * getuid(), SEEK_SET);\r
-       fwrite(&lastlog_entry, 1, sizeof(lastlog_entry), lastlog);\r
-       fclose(lastlog);\r
-    }\r
-#endif\r
-\r
-    pty_stamped_utmp = 1;\r
-\r
-}\r
-\r
-static void cleanup_utmp(void)\r
-{\r
-    struct timeval tv;\r
-\r
-    if (!pty_stamped_utmp)\r
-       return;\r
-\r
-    utmp_entry.ut_type = DEAD_PROCESS;\r
-    memset(utmp_entry.ut_user, 0, lenof(utmp_entry.ut_user));\r
-    gettimeofday(&tv, NULL);\r
-    utmp_entry.ut_tv.tv_sec = tv.tv_sec;\r
-    utmp_entry.ut_tv.tv_usec = tv.tv_usec;\r
-\r
-    updwtmpx(WTMPX_FILE, &utmp_entry);\r
-\r
-    memset(utmp_entry.ut_line, 0, lenof(utmp_entry.ut_line));\r
-    utmp_entry.ut_tv.tv_sec = 0;\r
-    utmp_entry.ut_tv.tv_usec = 0;\r
-\r
-    setutxent();\r
-    pututxline(&utmp_entry);\r
-    endutxent();\r
-\r
-    pty_stamped_utmp = 0;             /* ensure we never double-cleanup */\r
-}\r
-#endif\r
-\r
-static void sigchld_handler(int signum)\r
-{\r
-    if (write(pty_signal_pipe[1], "x", 1) <= 0)\r
-       /* not much we can do about it */;\r
-}\r
-\r
-#ifndef OMIT_UTMP\r
-static void fatal_sig_handler(int signum)\r
-{\r
-    putty_signal(signum, SIG_DFL);\r
-    cleanup_utmp();\r
-    setuid(getuid());\r
-    raise(signum);\r
-}\r
-#endif\r
-\r
-static int pty_open_slave(Pty pty)\r
-{\r
-    if (pty->slave_fd < 0) {\r
-       pty->slave_fd = open(pty->name, O_RDWR);\r
-        cloexec(pty->slave_fd);\r
-    }\r
-\r
-    return pty->slave_fd;\r
-}\r
-\r
-static void pty_open_master(Pty pty)\r
-{\r
-#ifdef BSD_PTYS\r
-    const char chars1[] = "pqrstuvwxyz";\r
-    const char chars2[] = "0123456789abcdef";\r
-    const char *p1, *p2;\r
-    char master_name[20];\r
-    struct group *gp;\r
-\r
-    for (p1 = chars1; *p1; p1++)\r
-       for (p2 = chars2; *p2; p2++) {\r
-           sprintf(master_name, "/dev/pty%c%c", *p1, *p2);\r
-           pty->master_fd = open(master_name, O_RDWR);\r
-           if (pty->master_fd >= 0) {\r
-               if (geteuid() == 0 ||\r
-                   access(master_name, R_OK | W_OK) == 0) {\r
-                   /*\r
-                    * We must also check at this point that we are\r
-                    * able to open the slave side of the pty. We\r
-                    * wouldn't want to allocate the wrong master,\r
-                    * get all the way down to forking, and _then_\r
-                    * find we're unable to open the slave.\r
-                    */\r
-                   strcpy(pty->name, master_name);\r
-                   pty->name[5] = 't'; /* /dev/ptyXX -> /dev/ttyXX */\r
-\r
-                    cloexec(pty->master_fd);\r
-\r
-                   if (pty_open_slave(pty) >= 0 &&\r
-                       access(pty->name, R_OK | W_OK) == 0)\r
-                       goto got_one;\r
-                   if (pty->slave_fd > 0)\r
-                       close(pty->slave_fd);\r
-                   pty->slave_fd = -1;\r
-               }\r
-               close(pty->master_fd);\r
-           }\r
-       }\r
-\r
-    /* If we get here, we couldn't get a tty at all. */\r
-    fprintf(stderr, "pterm: unable to open a pseudo-terminal device\n");\r
-    exit(1);\r
-\r
-    got_one:\r
-\r
-    /* We need to chown/chmod the /dev/ttyXX device. */\r
-    gp = getgrnam("tty");\r
-    chown(pty->name, getuid(), gp ? gp->gr_gid : -1);\r
-    chmod(pty->name, 0600);\r
-#else\r
-    pty->master_fd = open("/dev/ptmx", O_RDWR);\r
-\r
-    if (pty->master_fd < 0) {\r
-       perror("/dev/ptmx: open");\r
-       exit(1);\r
-    }\r
-\r
-    if (grantpt(pty->master_fd) < 0) {\r
-       perror("grantpt");\r
-       exit(1);\r
-    }\r
-    \r
-    if (unlockpt(pty->master_fd) < 0) {\r
-       perror("unlockpt");\r
-       exit(1);\r
-    }\r
-\r
-    cloexec(pty->master_fd);\r
-\r
-    pty->name[FILENAME_MAX-1] = '\0';\r
-    strncpy(pty->name, ptsname(pty->master_fd), FILENAME_MAX-1);\r
-#endif\r
-\r
-    {\r
-        /*\r
-         * Set the pty master into non-blocking mode.\r
-         */\r
-        int fl;\r
-       fl = fcntl(pty->master_fd, F_GETFL);\r
-       if (fl != -1 && !(fl & O_NONBLOCK))\r
-           fcntl(pty->master_fd, F_SETFL, fl | O_NONBLOCK);\r
-    }\r
-\r
-    if (!ptys_by_fd)\r
-       ptys_by_fd = newtree234(pty_compare_by_fd);\r
-    add234(ptys_by_fd, pty);\r
-}\r
-\r
-/*\r
- * Pre-initialisation. This is here to get around the fact that GTK\r
- * doesn't like being run in setuid/setgid programs (probably\r
- * sensibly). So before we initialise GTK - and therefore before we\r
- * even process the command line - we check to see if we're running\r
- * set[ug]id. If so, we open our pty master _now_, chown it as\r
- * necessary, and drop privileges. We can always close it again\r
- * later. If we're potentially going to be doing utmp as well, we\r
- * also fork off a utmp helper process and communicate with it by\r
- * means of a pipe; the utmp helper will keep privileges in order\r
- * to clean up utmp when we exit (i.e. when its end of our pipe\r
- * closes).\r
- */\r
-void pty_pre_init(void)\r
-{\r
-    Pty pty;\r
-\r
-#ifndef OMIT_UTMP\r
-    pid_t pid;\r
-    int pipefd[2];\r
-#endif\r
-\r
-    pty = single_pty = snew(struct pty_tag);\r
-    bufchain_init(&pty->output_data);\r
-\r
-    /* set the child signal handler straight away; it needs to be set\r
-     * before we ever fork. */\r
-    putty_signal(SIGCHLD, sigchld_handler);\r
-    pty->master_fd = pty->slave_fd = -1;\r
-#ifndef OMIT_UTMP\r
-    pty_stamped_utmp = FALSE;\r
-#endif\r
-\r
-    if (geteuid() != getuid() || getegid() != getgid()) {\r
-       pty_open_master(pty);\r
-    }\r
-\r
-#ifndef OMIT_UTMP\r
-    /*\r
-     * Fork off the utmp helper.\r
-     */\r
-    if (pipe(pipefd) < 0) {\r
-       perror("pterm: pipe");\r
-       exit(1);\r
-    }\r
-    cloexec(pipefd[0]);\r
-    cloexec(pipefd[1]);\r
-    pid = fork();\r
-    if (pid < 0) {\r
-       perror("pterm: fork");\r
-       exit(1);\r
-    } else if (pid == 0) {\r
-       char display[128], buffer[128];\r
-       int dlen, ret;\r
-\r
-       close(pipefd[1]);\r
-       /*\r
-        * Now sit here until we receive a display name from the\r
-        * other end of the pipe, and then stamp utmp. Unstamp utmp\r
-        * again, and exit, when the pipe closes.\r
-        */\r
-\r
-       dlen = 0;\r
-       while (1) {\r
-           \r
-           ret = read(pipefd[0], buffer, lenof(buffer));\r
-           if (ret <= 0) {\r
-               cleanup_utmp();\r
-               _exit(0);\r
-           } else if (!pty_stamped_utmp) {\r
-               if (dlen < lenof(display))\r
-                   memcpy(display+dlen, buffer,\r
-                          min(ret, lenof(display)-dlen));\r
-               if (buffer[ret-1] == '\0') {\r
-                   /*\r
-                    * Now we have a display name. NUL-terminate\r
-                    * it, and stamp utmp.\r
-                    */\r
-                   display[lenof(display)-1] = '\0';\r
-                   /*\r
-                    * Trap as many fatal signals as we can in the\r
-                    * hope of having the best possible chance to\r
-                    * clean up utmp before termination. We are\r
-                    * unfortunately unprotected against SIGKILL,\r
-                    * but that's life.\r
-                    */\r
-                   putty_signal(SIGHUP, fatal_sig_handler);\r
-                   putty_signal(SIGINT, fatal_sig_handler);\r
-                   putty_signal(SIGQUIT, fatal_sig_handler);\r
-                   putty_signal(SIGILL, fatal_sig_handler);\r
-                   putty_signal(SIGABRT, fatal_sig_handler);\r
-                   putty_signal(SIGFPE, fatal_sig_handler);\r
-                   putty_signal(SIGPIPE, fatal_sig_handler);\r
-                   putty_signal(SIGALRM, fatal_sig_handler);\r
-                   putty_signal(SIGTERM, fatal_sig_handler);\r
-                   putty_signal(SIGSEGV, fatal_sig_handler);\r
-                   putty_signal(SIGUSR1, fatal_sig_handler);\r
-                   putty_signal(SIGUSR2, fatal_sig_handler);\r
-#ifdef SIGBUS\r
-                   putty_signal(SIGBUS, fatal_sig_handler);\r
-#endif\r
-#ifdef SIGPOLL\r
-                   putty_signal(SIGPOLL, fatal_sig_handler);\r
-#endif\r
-#ifdef SIGPROF\r
-                   putty_signal(SIGPROF, fatal_sig_handler);\r
-#endif\r
-#ifdef SIGSYS\r
-                   putty_signal(SIGSYS, fatal_sig_handler);\r
-#endif\r
-#ifdef SIGTRAP\r
-                   putty_signal(SIGTRAP, fatal_sig_handler);\r
-#endif\r
-#ifdef SIGVTALRM\r
-                   putty_signal(SIGVTALRM, fatal_sig_handler);\r
-#endif\r
-#ifdef SIGXCPU\r
-                   putty_signal(SIGXCPU, fatal_sig_handler);\r
-#endif\r
-#ifdef SIGXFSZ\r
-                   putty_signal(SIGXFSZ, fatal_sig_handler);\r
-#endif\r
-#ifdef SIGIO\r
-                   putty_signal(SIGIO, fatal_sig_handler);\r
-#endif\r
-                   setup_utmp(pty->name, display);\r
-               }\r
-           }\r
-       }\r
-    } else {\r
-       close(pipefd[0]);\r
-       pty_utmp_helper_pid = pid;\r
-       pty_utmp_helper_pipe = pipefd[1];\r
-    }\r
-#endif\r
-\r
-    /* Drop privs. */\r
-    {\r
-#ifndef HAVE_NO_SETRESUID\r
-       int gid = getgid(), uid = getuid();\r
-       int setresgid(gid_t, gid_t, gid_t);\r
-       int setresuid(uid_t, uid_t, uid_t);\r
-       setresgid(gid, gid, gid);\r
-       setresuid(uid, uid, uid);\r
-#else\r
-       setgid(getgid());\r
-       setuid(getuid());\r
-#endif\r
-    }\r
-}\r
-\r
-int pty_real_select_result(Pty pty, int event, int status)\r
-{\r
-    char buf[4096];\r
-    int ret;\r
-    int finished = FALSE;\r
-\r
-    if (event < 0) {\r
-       /*\r
-        * We've been called because our child process did\r
-        * something. `status' tells us what.\r
-        */\r
-       if ((WIFEXITED(status) || WIFSIGNALED(status))) {\r
-           /*\r
-            * The primary child process died. We could keep\r
-            * the terminal open for remaining subprocesses to\r
-            * output to, but conventional wisdom seems to feel\r
-            * that that's the Wrong Thing for an xterm-alike,\r
-            * so we bail out now (though we don't necessarily\r
-            * _close_ the window, depending on the state of\r
-            * Close On Exit). This would be easy enough to\r
-            * change or make configurable if necessary.\r
-            */\r
-           pty->exit_code = status;\r
-           pty->child_dead = TRUE;\r
-           del234(ptys_by_pid, pty);\r
-           finished = TRUE;\r
-       }\r
-    } else {\r
-       if (event == 1) {\r
-\r
-           ret = read(pty->master_fd, buf, sizeof(buf));\r
-\r
-           /*\r
-            * Clean termination condition is that either ret == 0, or ret\r
-            * < 0 and errno == EIO. Not sure why the latter, but it seems\r
-            * to happen. Boo.\r
-            */\r
-           if (ret == 0 || (ret < 0 && errno == EIO)) {\r
-               /*\r
-                * We assume a clean exit if the pty has closed but the\r
-                * actual child process hasn't. The only way I can\r
-                * imagine this happening is if it detaches itself from\r
-                * the pty and goes daemonic - in which case the\r
-                * expected usage model would precisely _not_ be for\r
-                * the pterm window to hang around!\r
-                */\r
-               finished = TRUE;\r
-               if (!pty->child_dead)\r
-                   pty->exit_code = 0;\r
-           } else if (ret < 0) {\r
-               perror("read pty master");\r
-               exit(1);\r
-           } else if (ret > 0) {\r
-               from_backend(pty->frontend, 0, buf, ret);\r
-           }\r
-       } else if (event == 2) {\r
-            /*\r
-             * Attempt to send data down the pty.\r
-             */\r
-            pty_try_write(pty);\r
-        }\r
-    }\r
-\r
-    if (finished && !pty->finished) {\r
-       uxsel_del(pty->master_fd);\r
-       pty_close(pty);\r
-       pty->master_fd = -1;\r
-\r
-       pty->finished = TRUE;\r
-\r
-       /*\r
-        * This is a slight layering-violation sort of hack: only\r
-        * if we're not closing on exit (COE is set to Never, or to\r
-        * Only On Clean and it wasn't a clean exit) do we output a\r
-        * `terminated' message.\r
-        */\r
-       if (pty->cfg.close_on_exit == FORCE_OFF ||\r
-           (pty->cfg.close_on_exit == AUTO && pty->exit_code != 0)) {\r
-           char message[512];\r
-           if (WIFEXITED(pty->exit_code))\r
-               sprintf(message, "\r\n[pterm: process terminated with exit"\r
-                       " code %d]\r\n", WEXITSTATUS(pty->exit_code));\r
-           else if (WIFSIGNALED(pty->exit_code))\r
-#ifdef HAVE_NO_STRSIGNAL\r
-               sprintf(message, "\r\n[pterm: process terminated on signal"\r
-                       " %d]\r\n", WTERMSIG(pty->exit_code));\r
-#else\r
-               sprintf(message, "\r\n[pterm: process terminated on signal"\r
-                       " %d (%.400s)]\r\n", WTERMSIG(pty->exit_code),\r
-                       strsignal(WTERMSIG(pty->exit_code)));\r
-#endif\r
-           from_backend(pty->frontend, 0, message, strlen(message));\r
-       }\r
-\r
-       notify_remote_exit(pty->frontend);\r
-    }\r
-\r
-    return !finished;\r
-}\r
-\r
-int pty_select_result(int fd, int event)\r
-{\r
-    int ret = TRUE;\r
-    Pty pty;\r
-\r
-    if (fd == pty_signal_pipe[0]) {\r
-       pid_t pid;\r
-       int status;\r
-       char c[1];\r
-\r
-       if (read(pty_signal_pipe[0], c, 1) <= 0)\r
-           /* ignore error */;\r
-       /* ignore its value; it'll be `x' */\r
-\r
-       do {\r
-           pid = waitpid(-1, &status, WNOHANG);\r
-\r
-           pty = find234(ptys_by_pid, &pid, pty_find_by_pid);\r
-\r
-           if (pty)\r
-               ret = ret && pty_real_select_result(pty, -1, status);\r
-       } while (pid > 0);\r
-    } else {\r
-       pty = find234(ptys_by_fd, &fd, pty_find_by_fd);\r
-\r
-       if (pty)\r
-           ret = ret && pty_real_select_result(pty, event, 0);\r
-    }\r
-\r
-    return ret;\r
-}\r
-\r
-static void pty_uxsel_setup(Pty pty)\r
-{\r
-    int rwx;\r
-\r
-    rwx = 1;                           /* always want to read from pty */\r
-    if (bufchain_size(&pty->output_data))\r
-        rwx |= 2;                      /* might also want to write to it */\r
-    uxsel_set(pty->master_fd, rwx, pty_select_result);\r
-\r
-    /*\r
-     * In principle this only needs calling once for all pty\r
-     * backend instances, but it's simplest just to call it every\r
-     * time; uxsel won't mind.\r
-     */\r
-    uxsel_set(pty_signal_pipe[0], 1, pty_select_result);\r
-}\r
-\r
-/*\r
- * Called to set up the pty.\r
- * \r
- * Returns an error message, or NULL on success.\r
- *\r
- * Also places the canonical host name into `realhost'. It must be\r
- * freed by the caller.\r
- */\r
-static const char *pty_init(void *frontend, void **backend_handle, Config *cfg,\r
-                           char *host, int port, char **realhost, int nodelay,\r
-                           int keepalive)\r
-{\r
-    int slavefd;\r
-    pid_t pid, pgrp;\r
-#ifndef NOT_X_WINDOWS                 /* for Mac OS X native compilation */\r
-    long windowid;\r
-#endif\r
-    Pty pty;\r
-\r
-    if (single_pty) {\r
-       pty = single_pty;\r
-    } else {\r
-       pty = snew(struct pty_tag);\r
-       pty->master_fd = pty->slave_fd = -1;\r
-#ifndef OMIT_UTMP\r
-       pty_stamped_utmp = FALSE;\r
-#endif\r
-    }\r
-\r
-    pty->frontend = frontend;\r
-    *backend_handle = NULL;           /* we can't sensibly use this, sadly */\r
-\r
-    pty->cfg = *cfg;                  /* structure copy */\r
-    pty->term_width = cfg->width;\r
-    pty->term_height = cfg->height;\r
-\r
-    if (pty->master_fd < 0)\r
-       pty_open_master(pty);\r
-\r
-    /*\r
-     * Set the backspace character to be whichever of ^H and ^? is\r
-     * specified by bksp_is_delete.\r
-     */\r
-    {\r
-       struct termios attrs;\r
-       tcgetattr(pty->master_fd, &attrs);\r
-       attrs.c_cc[VERASE] = cfg->bksp_is_delete ? '\177' : '\010';\r
-       tcsetattr(pty->master_fd, TCSANOW, &attrs);\r
-    }\r
-\r
-#ifndef OMIT_UTMP\r
-    /*\r
-     * Stamp utmp (that is, tell the utmp helper process to do so),\r
-     * or not.\r
-     */\r
-    if (!cfg->stamp_utmp) {\r
-       close(pty_utmp_helper_pipe);   /* just let the child process die */\r
-       pty_utmp_helper_pipe = -1;\r
-    } else {\r
-       char *location = get_x_display(pty->frontend);\r
-       int len = strlen(location)+1, pos = 0;   /* +1 to include NUL */\r
-       while (pos < len) {\r
-           int ret = write(pty_utmp_helper_pipe, location+pos, len - pos);\r
-           if (ret < 0) {\r
-               perror("pterm: writing to utmp helper process");\r
-               close(pty_utmp_helper_pipe);   /* arrgh, just give up */\r
-               pty_utmp_helper_pipe = -1;\r
-               break;\r
-           }\r
-           pos += ret;\r
-       }\r
-    }\r
-#endif\r
-\r
-#ifndef NOT_X_WINDOWS                 /* for Mac OS X native compilation */\r
-    windowid = get_windowid(pty->frontend);\r
-#endif\r
-\r
-    /*\r
-     * Fork and execute the command.\r
-     */\r
-    pid = fork();\r
-    if (pid < 0) {\r
-       perror("fork");\r
-       exit(1);\r
-    }\r
-\r
-    if (pid == 0) {\r
-       /*\r
-        * We are the child.\r
-        */\r
-\r
-       slavefd = pty_open_slave(pty);\r
-       if (slavefd < 0) {\r
-           perror("slave pty: open");\r
-           _exit(1);\r
-       }\r
-\r
-       close(pty->master_fd);\r
-       fcntl(slavefd, F_SETFD, 0);    /* don't close on exec */\r
-       dup2(slavefd, 0);\r
-       dup2(slavefd, 1);\r
-       dup2(slavefd, 2);\r
-       close(slavefd);\r
-       setsid();\r
-#ifdef TIOCSCTTY\r
-       ioctl(0, TIOCSCTTY, 1);\r
-#endif\r
-       pgrp = getpid();\r
-       tcsetpgrp(0, pgrp);\r
-       setpgid(pgrp, pgrp);\r
-       close(open(pty->name, O_WRONLY, 0));\r
-       setpgid(pgrp, pgrp);\r
-       {\r
-           char *term_env_var = dupprintf("TERM=%s", cfg->termtype);\r
-           putenv(term_env_var);\r
-           /* We mustn't free term_env_var, as putenv links it into the\r
-            * environment in place.\r
-            */\r
-       }\r
-#ifndef NOT_X_WINDOWS                 /* for Mac OS X native compilation */\r
-       {\r
-           char *windowid_env_var = dupprintf("WINDOWID=%ld", windowid);\r
-           putenv(windowid_env_var);\r
-           /* We mustn't free windowid_env_var, as putenv links it into the\r
-            * environment in place.\r
-            */\r
-       }\r
-#endif\r
-       {\r
-           char *e = cfg->environmt;\r
-           char *var, *varend, *val, *varval;\r
-           while (*e) {\r
-               var = e;\r
-               while (*e && *e != '\t') e++;\r
-               varend = e;\r
-               if (*e == '\t') e++;\r
-               val = e;\r
-               while (*e) e++;\r
-               e++;\r
-\r
-               varval = dupprintf("%.*s=%s", varend-var, var, val);\r
-               putenv(varval);\r
-               /*\r
-                * We must not free varval, since putenv links it\r
-                * into the environment _in place_. Weird, but\r
-                * there we go. Memory usage will be rationalised\r
-                * as soon as we exec anyway.\r
-                */\r
-           }\r
-       }\r
-\r
-       /*\r
-        * SIGINT, SIGQUIT and SIGPIPE may have been set to ignored by\r
-        * our parent, particularly by things like sh -c 'pterm &' and\r
-        * some window or session managers. SIGCHLD, meanwhile, was\r
-        * blocked during pt_main() startup. Reverse all this for our\r
-        * child process.\r
-        */\r
-       putty_signal(SIGINT, SIG_DFL);\r
-       putty_signal(SIGQUIT, SIG_DFL);\r
-       putty_signal(SIGPIPE, SIG_DFL);\r
-       block_signal(SIGCHLD, 0);\r
-       if (pty_argv)\r
-           execvp(pty_argv[0], pty_argv);\r
-       else {\r
-           char *shell = getenv("SHELL");\r
-           char *shellname;\r
-           if (cfg->login_shell) {\r
-               char *p = strrchr(shell, '/');\r
-               shellname = snewn(2+strlen(shell), char);\r
-               p = p ? p+1 : shell;\r
-               sprintf(shellname, "-%s", p);\r
-           } else\r
-               shellname = shell;\r
-           execl(getenv("SHELL"), shellname, (void *)NULL);\r
-       }\r
-\r
-       /*\r
-        * If we're here, exec has gone badly foom.\r
-        */\r
-       perror("exec");\r
-       _exit(127);\r
-    } else {\r
-       pty->child_pid = pid;\r
-       pty->child_dead = FALSE;\r
-       pty->finished = FALSE;\r
-       if (pty->slave_fd > 0)\r
-           close(pty->slave_fd);\r
-       if (!ptys_by_pid)\r
-           ptys_by_pid = newtree234(pty_compare_by_pid);\r
-       add234(ptys_by_pid, pty);\r
-    }\r
-\r
-    if (pty_signal_pipe[0] < 0) {\r
-       if (pipe(pty_signal_pipe) < 0) {\r
-           perror("pipe");\r
-           exit(1);\r
-       }\r
-       cloexec(pty_signal_pipe[0]);\r
-       cloexec(pty_signal_pipe[1]);\r
-    }\r
-    pty_uxsel_setup(pty);\r
-\r
-    *backend_handle = pty;\r
-\r
-    *realhost = dupprintf("\0");\r
-\r
-    return NULL;\r
-}\r
-\r
-static void pty_reconfig(void *handle, Config *cfg)\r
-{\r
-    Pty pty = (Pty)handle;\r
-    /*\r
-     * We don't have much need to reconfigure this backend, but\r
-     * unfortunately we do need to pick up the setting of Close On\r
-     * Exit so we know whether to give a `terminated' message.\r
-     */\r
-    pty->cfg = *cfg;                  /* structure copy */\r
-}\r
-\r
-/*\r
- * Stub routine (never called in pterm).\r
- */\r
-static void pty_free(void *handle)\r
-{\r
-    Pty pty = (Pty)handle;\r
-\r
-    /* Either of these may fail `not found'. That's fine with us. */\r
-    del234(ptys_by_pid, pty);\r
-    del234(ptys_by_fd, pty);\r
-\r
-    sfree(pty);\r
-}\r
-\r
-static void pty_try_write(Pty pty)\r
-{\r
-    void *data;\r
-    int len, ret;\r
-\r
-    assert(pty->master_fd >= 0);\r
-\r
-    while (bufchain_size(&pty->output_data) > 0) {\r
-        bufchain_prefix(&pty->output_data, &data, &len);\r
-       ret = write(pty->master_fd, data, len);\r
-\r
-        if (ret < 0 && (errno == EWOULDBLOCK)) {\r
-            /*\r
-             * We've sent all we can for the moment.\r
-             */\r
-            break;\r
-        }\r
-       if (ret < 0) {\r
-           perror("write pty master");\r
-           exit(1);\r
-       }\r
-       bufchain_consume(&pty->output_data, ret);\r
-    }\r
-\r
-    pty_uxsel_setup(pty);\r
-}\r
-\r
-/*\r
- * Called to send data down the pty.\r
- */\r
-static int pty_send(void *handle, char *buf, int len)\r
-{\r
-    Pty pty = (Pty)handle;\r
-\r
-    if (pty->master_fd < 0)\r
-       return 0;                      /* ignore all writes if fd closed */\r
-\r
-    bufchain_add(&pty->output_data, buf, len);\r
-    pty_try_write(pty);\r
-\r
-    return bufchain_size(&pty->output_data);\r
-}\r
-\r
-static void pty_close(Pty pty)\r
-{\r
-    if (pty->master_fd >= 0) {\r
-       close(pty->master_fd);\r
-       pty->master_fd = -1;\r
-    }\r
-#ifndef OMIT_UTMP\r
-    if (pty_utmp_helper_pipe >= 0) {\r
-       close(pty_utmp_helper_pipe);   /* this causes utmp to be cleaned up */\r
-       pty_utmp_helper_pipe = -1;\r
-    }\r
-#endif\r
-}\r
-\r
-/*\r
- * Called to query the current socket sendability status.\r
- */\r
-static int pty_sendbuffer(void *handle)\r
-{\r
-    /* Pty pty = (Pty)handle; */\r
-    return 0;\r
-}\r
-\r
-/*\r
- * Called to set the size of the window\r
- */\r
-static void pty_size(void *handle, int width, int height)\r
-{\r
-    Pty pty = (Pty)handle;\r
-    struct winsize size;\r
-\r
-    pty->term_width = width;\r
-    pty->term_height = height;\r
-\r
-    size.ws_row = (unsigned short)pty->term_height;\r
-    size.ws_col = (unsigned short)pty->term_width;\r
-    size.ws_xpixel = (unsigned short) pty->term_width *\r
-       font_dimension(pty->frontend, 0);\r
-    size.ws_ypixel = (unsigned short) pty->term_height *\r
-       font_dimension(pty->frontend, 1);\r
-    ioctl(pty->master_fd, TIOCSWINSZ, (void *)&size);\r
-    return;\r
-}\r
-\r
-/*\r
- * Send special codes.\r
- */\r
-static void pty_special(void *handle, Telnet_Special code)\r
-{\r
-    /* Pty pty = (Pty)handle; */\r
-    /* Do nothing! */\r
-    return;\r
-}\r
-\r
-/*\r
- * Return a list of the special codes that make sense in this\r
- * protocol.\r
- */\r
-static const struct telnet_special *pty_get_specials(void *handle)\r
-{\r
-    /* Pty pty = (Pty)handle; */\r
-    /*\r
-     * Hmm. When I get round to having this actually usable, it\r
-     * might be quite nice to have the ability to deliver a few\r
-     * well chosen signals to the child process - SIGINT, SIGTERM,\r
-     * SIGKILL at least.\r
-     */\r
-    return NULL;\r
-}\r
-\r
-static int pty_connected(void *handle)\r
-{\r
-    /* Pty pty = (Pty)handle; */\r
-    return TRUE;\r
-}\r
-\r
-static int pty_sendok(void *handle)\r
-{\r
-    /* Pty pty = (Pty)handle; */\r
-    return 1;\r
-}\r
-\r
-static void pty_unthrottle(void *handle, int backlog)\r
-{\r
-    /* Pty pty = (Pty)handle; */\r
-    /* do nothing */\r
-}\r
-\r
-static int pty_ldisc(void *handle, int option)\r
-{\r
-    /* Pty pty = (Pty)handle; */\r
-    return 0;                         /* neither editing nor echoing */\r
-}\r
-\r
-static void pty_provide_ldisc(void *handle, void *ldisc)\r
-{\r
-    /* Pty pty = (Pty)handle; */\r
-    /* This is a stub. */\r
-}\r
-\r
-static void pty_provide_logctx(void *handle, void *logctx)\r
-{\r
-    /* Pty pty = (Pty)handle; */\r
-    /* This is a stub. */\r
-}\r
-\r
-static int pty_exitcode(void *handle)\r
-{\r
-    Pty pty = (Pty)handle;\r
-    if (!pty->finished)\r
-       return -1;                     /* not dead yet */\r
-    else\r
-       return pty->exit_code;\r
-}\r
-\r
-static int pty_cfg_info(void *handle)\r
-{\r
-    /* Pty pty = (Pty)handle; */\r
-    return 0;\r
-}\r
-\r
-Backend pty_backend = {\r
-    pty_init,\r
-    pty_free,\r
-    pty_reconfig,\r
-    pty_send,\r
-    pty_sendbuffer,\r
-    pty_size,\r
-    pty_special,\r
-    pty_get_specials,\r
-    pty_connected,\r
-    pty_exitcode,\r
-    pty_sendok,\r
-    pty_ldisc,\r
-    pty_provide_ldisc,\r
-    pty_provide_logctx,\r
-    pty_unthrottle,\r
-    pty_cfg_info,\r
-    "pty",\r
-    -1,\r
-    0\r
-};\r