]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - unix/uxpty.c
Some hosts don't have TIOCSCTTY. Don't try to use it on them.
[PuTTY.git] / unix / uxpty.c
1 /*
2  * Pseudo-tty backend for pterm.
3  */
4
5 #define _GNU_SOURCE
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <signal.h>
12 #include <fcntl.h>
13 #include <termios.h>
14 #include <grp.h>
15 #include <utmp.h>
16 #include <pwd.h>
17 #include <time.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/wait.h>
21 #include <sys/ioctl.h>
22 #include <errno.h>
23
24 #include "putty.h"
25 #include "tree234.h"
26
27 #ifndef OMIT_UTMP
28 #include <utmpx.h>
29 #endif
30
31 #ifndef FALSE
32 #define FALSE 0
33 #endif
34 #ifndef TRUE
35 #define TRUE 1
36 #endif
37
38 /* updwtmpx() needs the name of the wtmp file.  Try to find it. */
39 #ifndef WTMPX_FILE
40 #ifdef _PATH_WTMPX
41 #define WTMPX_FILE _PATH_WTMPX
42 #else
43 #define WTMPX_FILE "/var/log/wtmpx"
44 #endif
45 #endif
46
47 #ifndef LASTLOG_FILE
48 #ifdef _PATH_LASTLOG
49 #define LASTLOG_FILE _PATH_LASTLOG
50 #else
51 #define LASTLOG_FILE "/var/log/lastlog"
52 #endif
53 #endif
54
55 /*
56  * Set up a default for vaguely sane systems. The idea is that if
57  * OMIT_UTMP is not defined, then at least one of the symbols which
58  * enable particular forms of utmp processing should be, if only so
59  * that a link error can warn you that you should have defined
60  * OMIT_UTMP if you didn't want any. Currently HAVE_PUTUTLINE is
61  * the only such symbol.
62  */
63 #ifndef OMIT_UTMP
64 #if !defined HAVE_PUTUTLINE
65 #define HAVE_PUTUTLINE
66 #endif
67 #endif
68
69 typedef struct pty_tag *Pty;
70
71 /*
72  * The pty_signal_pipe, along with the SIGCHLD handler, must be
73  * process-global rather than session-specific.
74  */
75 static int pty_signal_pipe[2] = { -1, -1 };   /* obviously bogus initial val */
76
77 struct pty_tag {
78     Config cfg;
79     int master_fd, slave_fd;
80     void *frontend;
81     char name[FILENAME_MAX];
82     int child_pid;
83     int term_width, term_height;
84     int child_dead, finished;
85     int exit_code;
86 };
87
88 /*
89  * We store our pty backends in a tree sorted by master fd, so that
90  * when we get an uxsel notification we know which backend instance
91  * is the owner of the pty that caused it.
92  */
93 static int pty_compare_by_fd(void *av, void *bv)
94 {
95     Pty a = (Pty)av;
96     Pty b = (Pty)bv;
97
98     if (a->master_fd < b->master_fd)
99         return -1;
100     else if (a->master_fd > b->master_fd)
101         return +1;
102     return 0;
103 }
104
105 static int pty_find_by_fd(void *av, void *bv)
106 {
107     int a = *(int *)av;
108     Pty b = (Pty)bv;
109
110     if (a < b->master_fd)
111         return -1;
112     else if (a > b->master_fd)
113         return +1;
114     return 0;
115 }
116
117 static tree234 *ptys_by_fd = NULL;
118
119 /*
120  * We also have a tree sorted by child pid, so that when we wait()
121  * in response to the signal we know which backend instance is the
122  * owner of the process that caused the signal.
123  */
124 static int pty_compare_by_pid(void *av, void *bv)
125 {
126     Pty a = (Pty)av;
127     Pty b = (Pty)bv;
128
129     if (a->child_pid < b->child_pid)
130         return -1;
131     else if (a->child_pid > b->child_pid)
132         return +1;
133     return 0;
134 }
135
136 static int pty_find_by_pid(void *av, void *bv)
137 {
138     int a = *(int *)av;
139     Pty b = (Pty)bv;
140
141     if (a < b->child_pid)
142         return -1;
143     else if (a > b->child_pid)
144         return +1;
145     return 0;
146 }
147
148 static tree234 *ptys_by_pid = NULL;
149
150 /*
151  * If we are using pty_pre_init(), it will need to have already
152  * allocated a pty structure, which we must then return from
153  * pty_init() rather than allocating a new one. Here we store that
154  * structure between allocation and use.
155  * 
156  * Note that although most of this module is entirely capable of
157  * handling multiple ptys in a single process, pty_pre_init() is
158  * fundamentally _dependent_ on there being at most one pty per
159  * process, so the normal static-data constraints don't apply.
160  * 
161  * Likewise, since utmp is only used via pty_pre_init, it too must
162  * be single-instance, so we can declare utmp-related variables
163  * here.
164  */
165 static Pty single_pty = NULL;
166
167 #ifndef OMIT_UTMP
168 static int pty_utmp_helper_pid, pty_utmp_helper_pipe;
169 static int pty_stamped_utmp;
170 static struct utmpx utmp_entry;
171 #endif
172
173 /*
174  * pty_argv is a grievous hack to allow a proper argv to be passed
175  * through from the Unix command line. Again, it doesn't really
176  * make sense outside a one-pty-per-process setup.
177  */
178 char **pty_argv;
179
180 static void pty_close(Pty pty);
181
182 #ifndef OMIT_UTMP
183 static void setup_utmp(char *ttyname, char *location)
184 {
185 #ifdef HAVE_LASTLOG
186     struct lastlog lastlog_entry;
187     FILE *lastlog;
188 #endif
189     struct passwd *pw;
190     struct timeval tv;
191
192     pw = getpwuid(getuid());
193     memset(&utmp_entry, 0, sizeof(utmp_entry));
194     utmp_entry.ut_type = USER_PROCESS;
195     utmp_entry.ut_pid = getpid();
196     strncpy(utmp_entry.ut_line, ttyname+5, lenof(utmp_entry.ut_line));
197     strncpy(utmp_entry.ut_id, ttyname+8, lenof(utmp_entry.ut_id));
198     strncpy(utmp_entry.ut_user, pw->pw_name, lenof(utmp_entry.ut_user));
199     strncpy(utmp_entry.ut_host, location, lenof(utmp_entry.ut_host));
200     /*
201      * Apparently there are some architectures where (struct
202      * utmpx).ut_tv is not essentially struct timeval (e.g. Linux
203      * amd64). Hence the temporary.
204      */
205     gettimeofday(&tv, NULL);
206     utmp_entry.ut_tv.tv_sec = tv.tv_sec;
207     utmp_entry.ut_tv.tv_usec = tv.tv_usec;
208
209     setutxent();
210     pututxline(&utmp_entry);
211     endutxent();
212
213     updwtmpx(WTMPX_FILE, &utmp_entry);
214
215 #ifdef HAVE_LASTLOG
216     memset(&lastlog_entry, 0, sizeof(lastlog_entry));
217     strncpy(lastlog_entry.ll_line, ttyname+5, lenof(lastlog_entry.ll_line));
218     strncpy(lastlog_entry.ll_host, location, lenof(lastlog_entry.ll_host));
219     time(&lastlog_entry.ll_time);
220     if ((lastlog = fopen(LASTLOG_FILE, "r+")) != NULL) {
221         fseek(lastlog, sizeof(lastlog_entry) * getuid(), SEEK_SET);
222         fwrite(&lastlog_entry, 1, sizeof(lastlog_entry), lastlog);
223         fclose(lastlog);
224     }
225 #endif
226
227     pty_stamped_utmp = 1;
228
229 }
230
231 static void cleanup_utmp(void)
232 {
233     struct timeval tv;
234
235     if (!pty_stamped_utmp)
236         return;
237
238     utmp_entry.ut_type = DEAD_PROCESS;
239     memset(utmp_entry.ut_user, 0, lenof(utmp_entry.ut_user));
240     gettimeofday(&tv, NULL);
241     utmp_entry.ut_tv.tv_sec = tv.tv_sec;
242     utmp_entry.ut_tv.tv_usec = tv.tv_usec;
243
244     updwtmpx(WTMPX_FILE, &utmp_entry);
245
246     memset(utmp_entry.ut_line, 0, lenof(utmp_entry.ut_line));
247     utmp_entry.ut_tv.tv_sec = 0;
248     utmp_entry.ut_tv.tv_usec = 0;
249
250     setutxent();
251     pututxline(&utmp_entry);
252     endutxent();
253
254     pty_stamped_utmp = 0;              /* ensure we never double-cleanup */
255 }
256 #endif
257
258 static void sigchld_handler(int signum)
259 {
260     write(pty_signal_pipe[1], "x", 1);
261 }
262
263 #ifndef OMIT_UTMP
264 static void fatal_sig_handler(int signum)
265 {
266     putty_signal(signum, SIG_DFL);
267     cleanup_utmp();
268     setuid(getuid());
269     raise(signum);
270 }
271 #endif
272
273 static int pty_open_slave(Pty pty)
274 {
275     if (pty->slave_fd < 0)
276         pty->slave_fd = open(pty->name, O_RDWR);
277
278     return pty->slave_fd;
279 }
280
281 static void pty_open_master(Pty pty)
282 {
283 #ifdef BSD_PTYS
284     const char chars1[] = "pqrstuvwxyz";
285     const char chars2[] = "0123456789abcdef";
286     const char *p1, *p2;
287     char master_name[20];
288     struct group *gp;
289
290     for (p1 = chars1; *p1; p1++)
291         for (p2 = chars2; *p2; p2++) {
292             sprintf(master_name, "/dev/pty%c%c", *p1, *p2);
293             pty->master_fd = open(master_name, O_RDWR);
294             if (pty->master_fd >= 0) {
295                 if (geteuid() == 0 ||
296                     access(master_name, R_OK | W_OK) == 0) {
297                     /*
298                      * We must also check at this point that we are
299                      * able to open the slave side of the pty. We
300                      * wouldn't want to allocate the wrong master,
301                      * get all the way down to forking, and _then_
302                      * find we're unable to open the slave.
303                      */
304                     strcpy(pty->name, master_name);
305                     pty->name[5] = 't'; /* /dev/ptyXX -> /dev/ttyXX */
306
307                     if (pty_open_slave(pty) >= 0 &&
308                         access(pty->name, R_OK | W_OK) == 0)
309                         goto got_one;
310                     if (pty->slave_fd > 0)
311                         close(pty->slave_fd);
312                     pty->slave_fd = -1;
313                 }
314                 close(pty->master_fd);
315             }
316         }
317
318     /* If we get here, we couldn't get a tty at all. */
319     fprintf(stderr, "pterm: unable to open a pseudo-terminal device\n");
320     exit(1);
321
322     got_one:
323
324     /* We need to chown/chmod the /dev/ttyXX device. */
325     gp = getgrnam("tty");
326     chown(pty->name, getuid(), gp ? gp->gr_gid : -1);
327     chmod(pty->name, 0600);
328 #else
329     pty->master_fd = open("/dev/ptmx", O_RDWR);
330
331     if (pty->master_fd < 0) {
332         perror("/dev/ptmx: open");
333         exit(1);
334     }
335
336     if (grantpt(pty->master_fd) < 0) {
337         perror("grantpt");
338         exit(1);
339     }
340     
341     if (unlockpt(pty->master_fd) < 0) {
342         perror("unlockpt");
343         exit(1);
344     }
345
346     pty->name[FILENAME_MAX-1] = '\0';
347     strncpy(pty->name, ptsname(pty->master_fd), FILENAME_MAX-1);
348 #endif
349
350     if (!ptys_by_fd)
351         ptys_by_fd = newtree234(pty_compare_by_fd);
352     add234(ptys_by_fd, pty);
353 }
354
355 /*
356  * Pre-initialisation. This is here to get around the fact that GTK
357  * doesn't like being run in setuid/setgid programs (probably
358  * sensibly). So before we initialise GTK - and therefore before we
359  * even process the command line - we check to see if we're running
360  * set[ug]id. If so, we open our pty master _now_, chown it as
361  * necessary, and drop privileges. We can always close it again
362  * later. If we're potentially going to be doing utmp as well, we
363  * also fork off a utmp helper process and communicate with it by
364  * means of a pipe; the utmp helper will keep privileges in order
365  * to clean up utmp when we exit (i.e. when its end of our pipe
366  * closes).
367  */
368 void pty_pre_init(void)
369 {
370     Pty pty;
371
372 #ifndef OMIT_UTMP
373     pid_t pid;
374     int pipefd[2];
375 #endif
376
377     pty = single_pty = snew(struct pty_tag);
378
379     /* set the child signal handler straight away; it needs to be set
380      * before we ever fork. */
381     putty_signal(SIGCHLD, sigchld_handler);
382     pty->master_fd = pty->slave_fd = -1;
383 #ifndef OMIT_UTMP
384     pty_stamped_utmp = FALSE;
385 #endif
386
387     if (geteuid() != getuid() || getegid() != getgid()) {
388         pty_open_master(pty);
389     }
390
391 #ifndef OMIT_UTMP
392     /*
393      * Fork off the utmp helper.
394      */
395     if (pipe(pipefd) < 0) {
396         perror("pterm: pipe");
397         exit(1);
398     }
399     pid = fork();
400     if (pid < 0) {
401         perror("pterm: fork");
402         exit(1);
403     } else if (pid == 0) {
404         char display[128], buffer[128];
405         int dlen, ret;
406
407         close(pipefd[1]);
408         /*
409          * Now sit here until we receive a display name from the
410          * other end of the pipe, and then stamp utmp. Unstamp utmp
411          * again, and exit, when the pipe closes.
412          */
413
414         dlen = 0;
415         while (1) {
416             
417             ret = read(pipefd[0], buffer, lenof(buffer));
418             if (ret <= 0) {
419                 cleanup_utmp();
420                 _exit(0);
421             } else if (!pty_stamped_utmp) {
422                 if (dlen < lenof(display))
423                     memcpy(display+dlen, buffer,
424                            min(ret, lenof(display)-dlen));
425                 if (buffer[ret-1] == '\0') {
426                     /*
427                      * Now we have a display name. NUL-terminate
428                      * it, and stamp utmp.
429                      */
430                     display[lenof(display)-1] = '\0';
431                     /*
432                      * Trap as many fatal signals as we can in the
433                      * hope of having the best possible chance to
434                      * clean up utmp before termination. We are
435                      * unfortunately unprotected against SIGKILL,
436                      * but that's life.
437                      */
438                     putty_signal(SIGHUP, fatal_sig_handler);
439                     putty_signal(SIGINT, fatal_sig_handler);
440                     putty_signal(SIGQUIT, fatal_sig_handler);
441                     putty_signal(SIGILL, fatal_sig_handler);
442                     putty_signal(SIGABRT, fatal_sig_handler);
443                     putty_signal(SIGFPE, fatal_sig_handler);
444                     putty_signal(SIGPIPE, fatal_sig_handler);
445                     putty_signal(SIGALRM, fatal_sig_handler);
446                     putty_signal(SIGTERM, fatal_sig_handler);
447                     putty_signal(SIGSEGV, fatal_sig_handler);
448                     putty_signal(SIGUSR1, fatal_sig_handler);
449                     putty_signal(SIGUSR2, fatal_sig_handler);
450 #ifdef SIGBUS
451                     putty_signal(SIGBUS, fatal_sig_handler);
452 #endif
453 #ifdef SIGPOLL
454                     putty_signal(SIGPOLL, fatal_sig_handler);
455 #endif
456 #ifdef SIGPROF
457                     putty_signal(SIGPROF, fatal_sig_handler);
458 #endif
459 #ifdef SIGSYS
460                     putty_signal(SIGSYS, fatal_sig_handler);
461 #endif
462 #ifdef SIGTRAP
463                     putty_signal(SIGTRAP, fatal_sig_handler);
464 #endif
465 #ifdef SIGVTALRM
466                     putty_signal(SIGVTALRM, fatal_sig_handler);
467 #endif
468 #ifdef SIGXCPU
469                     putty_signal(SIGXCPU, fatal_sig_handler);
470 #endif
471 #ifdef SIGXFSZ
472                     putty_signal(SIGXFSZ, fatal_sig_handler);
473 #endif
474 #ifdef SIGIO
475                     putty_signal(SIGIO, fatal_sig_handler);
476 #endif
477                     setup_utmp(pty->name, display);
478                 }
479             }
480         }
481     } else {
482         close(pipefd[0]);
483         pty_utmp_helper_pid = pid;
484         pty_utmp_helper_pipe = pipefd[1];
485     }
486 #endif
487
488     /* Drop privs. */
489     {
490 #ifndef HAVE_NO_SETRESUID
491         int gid = getgid(), uid = getuid();
492         int setresgid(gid_t, gid_t, gid_t);
493         int setresuid(uid_t, uid_t, uid_t);
494         setresgid(gid, gid, gid);
495         setresuid(uid, uid, uid);
496 #else
497         setgid(getgid());
498         setuid(getuid());
499 #endif
500     }
501 }
502
503 int pty_real_select_result(Pty pty, int event, int status)
504 {
505     char buf[4096];
506     int ret;
507     int finished = FALSE;
508
509     if (event < 0) {
510         /*
511          * We've been called because our child process did
512          * something. `status' tells us what.
513          */
514         if ((WIFEXITED(status) || WIFSIGNALED(status))) {
515             /*
516              * The primary child process died. We could keep
517              * the terminal open for remaining subprocesses to
518              * output to, but conventional wisdom seems to feel
519              * that that's the Wrong Thing for an xterm-alike,
520              * so we bail out now (though we don't necessarily
521              * _close_ the window, depending on the state of
522              * Close On Exit). This would be easy enough to
523              * change or make configurable if necessary.
524              */
525             pty->exit_code = status;
526             pty->child_dead = TRUE;
527             del234(ptys_by_pid, pty);
528             finished = TRUE;
529         }
530     } else {
531         if (event == 1) {
532
533             ret = read(pty->master_fd, buf, sizeof(buf));
534
535             /*
536              * Clean termination condition is that either ret == 0, or ret
537              * < 0 and errno == EIO. Not sure why the latter, but it seems
538              * to happen. Boo.
539              */
540             if (ret == 0 || (ret < 0 && errno == EIO)) {
541                 /*
542                  * We assume a clean exit if the pty has closed but the
543                  * actual child process hasn't. The only way I can
544                  * imagine this happening is if it detaches itself from
545                  * the pty and goes daemonic - in which case the
546                  * expected usage model would precisely _not_ be for
547                  * the pterm window to hang around!
548                  */
549                 finished = TRUE;
550                 if (!pty->child_dead)
551                     pty->exit_code = 0;
552             } else if (ret < 0) {
553                 perror("read pty master");
554                 exit(1);
555             } else if (ret > 0) {
556                 from_backend(pty->frontend, 0, buf, ret);
557             }
558         }
559     }
560
561     if (finished && !pty->finished) {
562         uxsel_del(pty->master_fd);
563         pty_close(pty);
564         pty->master_fd = -1;
565
566         pty->finished = TRUE;
567
568         /*
569          * This is a slight layering-violation sort of hack: only
570          * if we're not closing on exit (COE is set to Never, or to
571          * Only On Clean and it wasn't a clean exit) do we output a
572          * `terminated' message.
573          */
574         if (pty->cfg.close_on_exit == FORCE_OFF ||
575             (pty->cfg.close_on_exit == AUTO && pty->exit_code != 0)) {
576             char message[512];
577             if (WIFEXITED(pty->exit_code))
578                 sprintf(message, "\r\n[pterm: process terminated with exit"
579                         " code %d]\r\n", WEXITSTATUS(pty->exit_code));
580             else if (WIFSIGNALED(pty->exit_code))
581 #ifdef HAVE_NO_STRSIGNAL
582                 sprintf(message, "\r\n[pterm: process terminated on signal"
583                         " %d]\r\n", WTERMSIG(pty->exit_code));
584 #else
585                 sprintf(message, "\r\n[pterm: process terminated on signal"
586                         " %d (%.400s)]\r\n", WTERMSIG(pty->exit_code),
587                         strsignal(WTERMSIG(pty->exit_code)));
588 #endif
589             from_backend(pty->frontend, 0, message, strlen(message));
590         }
591
592         notify_remote_exit(pty->frontend);
593     }
594
595     return !finished;
596 }
597
598 int pty_select_result(int fd, int event)
599 {
600     int ret = TRUE;
601     Pty pty;
602
603     if (fd == pty_signal_pipe[0]) {
604         pid_t pid;
605         int ipid;
606         int status;
607         char c[1];
608
609         read(pty_signal_pipe[0], c, 1); /* ignore its value; it'll be `x' */
610
611         do {
612             pid = waitpid(-1, &status, WNOHANG);
613
614             ipid = pid;
615             pty = find234(ptys_by_pid, &pid, pty_find_by_pid);
616
617             if (pty)
618                 ret = ret && pty_real_select_result(pty, -1, status);
619         } while (pid > 0);
620     } else {
621         pty = find234(ptys_by_fd, &fd, pty_find_by_fd);
622
623         if (pty)
624             ret = ret && pty_real_select_result(pty, event, 0);
625     }
626
627     return ret;
628 }
629
630 static void pty_uxsel_setup(Pty pty)
631 {
632     uxsel_set(pty->master_fd, 1, pty_select_result);
633
634     /*
635      * In principle this only needs calling once for all pty
636      * backend instances, but it's simplest just to call it every
637      * time; uxsel won't mind.
638      */
639     uxsel_set(pty_signal_pipe[0], 1, pty_select_result);
640 }
641
642 /*
643  * Called to set up the pty.
644  * 
645  * Returns an error message, or NULL on success.
646  *
647  * Also places the canonical host name into `realhost'. It must be
648  * freed by the caller.
649  */
650 static const char *pty_init(void *frontend, void **backend_handle, Config *cfg,
651                             char *host, int port, char **realhost, int nodelay,
652                             int keepalive)
653 {
654     int slavefd;
655     pid_t pid, pgrp;
656 #ifndef NOT_X_WINDOWS                  /* for Mac OS X native compilation */
657     long windowid;
658 #endif
659     Pty pty;
660
661     if (single_pty) {
662         pty = single_pty;
663     } else {
664         pty = snew(struct pty_tag);
665         pty->master_fd = pty->slave_fd = -1;
666 #ifndef OMIT_UTMP
667         pty_stamped_utmp = FALSE;
668 #endif
669     }
670
671     pty->frontend = frontend;
672     *backend_handle = NULL;            /* we can't sensibly use this, sadly */
673
674     pty->cfg = *cfg;                   /* structure copy */
675     pty->term_width = cfg->width;
676     pty->term_height = cfg->height;
677
678     if (pty->master_fd < 0)
679         pty_open_master(pty);
680
681     /*
682      * Set the backspace character to be whichever of ^H and ^? is
683      * specified by bksp_is_delete.
684      */
685     {
686         struct termios attrs;
687         tcgetattr(pty->master_fd, &attrs);
688         attrs.c_cc[VERASE] = cfg->bksp_is_delete ? '\177' : '\010';
689         tcsetattr(pty->master_fd, TCSANOW, &attrs);
690     }
691
692 #ifndef OMIT_UTMP
693     /*
694      * Stamp utmp (that is, tell the utmp helper process to do so),
695      * or not.
696      */
697     if (!cfg->stamp_utmp) {
698         close(pty_utmp_helper_pipe);   /* just let the child process die */
699         pty_utmp_helper_pipe = -1;
700     } else {
701         char *location = get_x_display(pty->frontend);
702         int len = strlen(location)+1, pos = 0;   /* +1 to include NUL */
703         while (pos < len) {
704             int ret = write(pty_utmp_helper_pipe, location+pos, len - pos);
705             if (ret < 0) {
706                 perror("pterm: writing to utmp helper process");
707                 close(pty_utmp_helper_pipe);   /* arrgh, just give up */
708                 pty_utmp_helper_pipe = -1;
709                 break;
710             }
711             pos += ret;
712         }
713     }
714 #endif
715
716 #ifndef NOT_X_WINDOWS                  /* for Mac OS X native compilation */
717     windowid = get_windowid(pty->frontend);
718 #endif
719
720     /*
721      * Fork and execute the command.
722      */
723     pid = fork();
724     if (pid < 0) {
725         perror("fork");
726         exit(1);
727     }
728
729     if (pid == 0) {
730         int i;
731         /*
732          * We are the child.
733          */
734
735         slavefd = pty_open_slave(pty);
736         if (slavefd < 0) {
737             perror("slave pty: open");
738             _exit(1);
739         }
740
741         close(pty->master_fd);
742         fcntl(slavefd, F_SETFD, 0);    /* don't close on exec */
743         dup2(slavefd, 0);
744         dup2(slavefd, 1);
745         dup2(slavefd, 2);
746         setsid();
747 #ifdef TIOCSCTTY
748         ioctl(slavefd, TIOCSCTTY, 1);
749 #endif
750         pgrp = getpid();
751         tcsetpgrp(slavefd, pgrp);
752         setpgid(pgrp, pgrp);
753         close(open(pty->name, O_WRONLY, 0));
754         setpgid(pgrp, pgrp);
755         /* Close everything _else_, for tidiness. */
756         for (i = 3; i < 1024; i++)
757             close(i);
758         {
759             char *term_env_var = dupprintf("TERM=%s", cfg->termtype);
760             putenv(term_env_var);
761             /* We mustn't free term_env_var, as putenv links it into the
762              * environment in place.
763              */
764         }
765 #ifndef NOT_X_WINDOWS                  /* for Mac OS X native compilation */
766         {
767             char *windowid_env_var = dupprintf("WINDOWID=%ld", windowid);
768             putenv(windowid_env_var);
769             /* We mustn't free windowid_env_var, as putenv links it into the
770              * environment in place.
771              */
772         }
773 #endif
774         {
775             char *e = cfg->environmt;
776             char *var, *varend, *val, *varval;
777             while (*e) {
778                 var = e;
779                 while (*e && *e != '\t') e++;
780                 varend = e;
781                 if (*e == '\t') e++;
782                 val = e;
783                 while (*e) e++;
784                 e++;
785
786                 varval = dupprintf("%.*s=%s", varend-var, var, val);
787                 putenv(varval);
788                 /*
789                  * We must not free varval, since putenv links it
790                  * into the environment _in place_. Weird, but
791                  * there we go. Memory usage will be rationalised
792                  * as soon as we exec anyway.
793                  */
794             }
795         }
796
797         /*
798          * SIGINT and SIGQUIT may have been set to ignored by our
799          * parent, particularly by things like sh -c 'pterm &' and
800          * some window managers. SIGCHLD, meanwhile, was blocked
801          * during pt_main() startup. Reverse all this for our child
802          * process.
803          */
804         putty_signal(SIGINT, SIG_DFL);
805         putty_signal(SIGQUIT, SIG_DFL);
806         block_signal(SIGCHLD, 0);
807         if (pty_argv)
808             execvp(pty_argv[0], pty_argv);
809         else {
810             char *shell = getenv("SHELL");
811             char *shellname;
812             if (cfg->login_shell) {
813                 char *p = strrchr(shell, '/');
814                 shellname = snewn(2+strlen(shell), char);
815                 p = p ? p+1 : shell;
816                 sprintf(shellname, "-%s", p);
817             } else
818                 shellname = shell;
819             execl(getenv("SHELL"), shellname, (void *)NULL);
820         }
821
822         /*
823          * If we're here, exec has gone badly foom.
824          */
825         perror("exec");
826         _exit(127);
827     } else {
828         pty->child_pid = pid;
829         pty->child_dead = FALSE;
830         pty->finished = FALSE;
831         if (pty->slave_fd > 0)
832             close(pty->slave_fd);
833         if (!ptys_by_pid)
834             ptys_by_pid = newtree234(pty_compare_by_pid);
835         add234(ptys_by_pid, pty);
836     }
837
838     if (pty_signal_pipe[0] < 0 && pipe(pty_signal_pipe) < 0) {
839         perror("pipe");
840         exit(1);
841     }
842     pty_uxsel_setup(pty);
843
844     *backend_handle = pty;
845
846     return NULL;
847 }
848
849 static void pty_reconfig(void *handle, Config *cfg)
850 {
851     Pty pty = (Pty)handle;
852     /*
853      * We don't have much need to reconfigure this backend, but
854      * unfortunately we do need to pick up the setting of Close On
855      * Exit so we know whether to give a `terminated' message.
856      */
857     pty->cfg = *cfg;                   /* structure copy */
858 }
859
860 /*
861  * Stub routine (never called in pterm).
862  */
863 static void pty_free(void *handle)
864 {
865     Pty pty = (Pty)handle;
866
867     /* Either of these may fail `not found'. That's fine with us. */
868     del234(ptys_by_pid, pty);
869     del234(ptys_by_fd, pty);
870
871     sfree(pty);
872 }
873
874 /*
875  * Called to send data down the pty.
876  */
877 static int pty_send(void *handle, char *buf, int len)
878 {
879     Pty pty = (Pty)handle;
880
881     if (pty->master_fd < 0)
882         return 0;                      /* ignore all writes if fd closed */
883
884     while (len > 0) {
885         int ret = write(pty->master_fd, buf, len);
886         if (ret < 0) {
887             perror("write pty master");
888             exit(1);
889         }
890         buf += ret;
891         len -= ret;
892     }
893     return 0;
894 }
895
896 static void pty_close(Pty pty)
897 {
898     if (pty->master_fd >= 0) {
899         close(pty->master_fd);
900         pty->master_fd = -1;
901     }
902 #ifndef OMIT_UTMP
903     if (pty_utmp_helper_pipe >= 0) {
904         close(pty_utmp_helper_pipe);   /* this causes utmp to be cleaned up */
905         pty_utmp_helper_pipe = -1;
906     }
907 #endif
908 }
909
910 /*
911  * Called to query the current socket sendability status.
912  */
913 static int pty_sendbuffer(void *handle)
914 {
915     /* Pty pty = (Pty)handle; */
916     return 0;
917 }
918
919 /*
920  * Called to set the size of the window
921  */
922 static void pty_size(void *handle, int width, int height)
923 {
924     Pty pty = (Pty)handle;
925     struct winsize size;
926
927     pty->term_width = width;
928     pty->term_height = height;
929
930     size.ws_row = (unsigned short)pty->term_height;
931     size.ws_col = (unsigned short)pty->term_width;
932     size.ws_xpixel = (unsigned short) pty->term_width *
933         font_dimension(pty->frontend, 0);
934     size.ws_ypixel = (unsigned short) pty->term_height *
935         font_dimension(pty->frontend, 1);
936     ioctl(pty->master_fd, TIOCSWINSZ, (void *)&size);
937     return;
938 }
939
940 /*
941  * Send special codes.
942  */
943 static void pty_special(void *handle, Telnet_Special code)
944 {
945     /* Pty pty = (Pty)handle; */
946     /* Do nothing! */
947     return;
948 }
949
950 /*
951  * Return a list of the special codes that make sense in this
952  * protocol.
953  */
954 static const struct telnet_special *pty_get_specials(void *handle)
955 {
956     /* Pty pty = (Pty)handle; */
957     /*
958      * Hmm. When I get round to having this actually usable, it
959      * might be quite nice to have the ability to deliver a few
960      * well chosen signals to the child process - SIGINT, SIGTERM,
961      * SIGKILL at least.
962      */
963     return NULL;
964 }
965
966 static Socket pty_socket(void *handle)
967 {
968     /* Pty pty = (Pty)handle; */
969     return NULL;                       /* shouldn't ever be needed */
970 }
971
972 static int pty_sendok(void *handle)
973 {
974     /* Pty pty = (Pty)handle; */
975     return 1;
976 }
977
978 static void pty_unthrottle(void *handle, int backlog)
979 {
980     /* Pty pty = (Pty)handle; */
981     /* do nothing */
982 }
983
984 static int pty_ldisc(void *handle, int option)
985 {
986     /* Pty pty = (Pty)handle; */
987     return 0;                          /* neither editing nor echoing */
988 }
989
990 static void pty_provide_ldisc(void *handle, void *ldisc)
991 {
992     /* Pty pty = (Pty)handle; */
993     /* This is a stub. */
994 }
995
996 static void pty_provide_logctx(void *handle, void *logctx)
997 {
998     /* Pty pty = (Pty)handle; */
999     /* This is a stub. */
1000 }
1001
1002 static int pty_exitcode(void *handle)
1003 {
1004     Pty pty = (Pty)handle;
1005     if (!pty->finished)
1006         return -1;                     /* not dead yet */
1007     else
1008         return pty->exit_code;
1009 }
1010
1011 static int pty_cfg_info(void *handle)
1012 {
1013     /* Pty pty = (Pty)handle; */
1014     return 0;
1015 }
1016
1017 Backend pty_backend = {
1018     pty_init,
1019     pty_free,
1020     pty_reconfig,
1021     pty_send,
1022     pty_sendbuffer,
1023     pty_size,
1024     pty_special,
1025     pty_get_specials,
1026     pty_socket,
1027     pty_exitcode,
1028     pty_sendok,
1029     pty_ldisc,
1030     pty_provide_ldisc,
1031     pty_provide_logctx,
1032     pty_unthrottle,
1033     pty_cfg_info,
1034     1
1035 };