New timing infrastructure. There's a new function schedule_timer()
[u/mdw/putty] / unix / pty.c
index 55282d2..50b548c 100644 (file)
@@ -14,7 +14,6 @@
 #define _XOPEN_SOURCE
 #define _XOPEN_SOURCE_EXTENDED
 #define _GNU_SOURCE
-#include <features.h>
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -28,6 +27,7 @@
 #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>
@@ -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;
 }
@@ -486,7 +495,8 @@ static void pty_uxsel_setup(void)
  * freed by the caller.
  */
 static const char *pty_init(void *frontend, void **backend_handle, Config *cfg,
-                           char *host, int port, char **realhost, int nodelay)
+                           char *host, int port, char **realhost, int nodelay,
+                           int keepalive)
 {
     int slavefd;
     pid_t pid, pgrp;
@@ -513,13 +523,15 @@ static const 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 const 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 const 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,6 +595,29 @@ static const 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
@@ -666,7 +703,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
 }
 
 /*