Trim wide text properly at the RH edge of the screen.
[u/mdw/putty] / unix / pty.c
CommitLineData
054d8535 1#define _XOPEN_SOURCE
88e6b9ca 2#define _XOPEN_SOURCE_EXTENDED
054d8535 3#include <features.h>
4
1709795f 5#include <stdio.h>
6#include <stdlib.h>
054d8535 7#include <string.h>
8#include <unistd.h>
a0e16eb1 9#include <signal.h>
054d8535 10#include <fcntl.h>
88e6b9ca 11#include <termios.h>
a0e16eb1 12#include <sys/types.h>
13#include <sys/wait.h>
88e6b9ca 14#include <sys/ioctl.h>
1709795f 15
16#include "putty.h"
17
18#ifndef FALSE
19#define FALSE 0
20#endif
21#ifndef TRUE
22#define TRUE 1
23#endif
24
054d8535 25int pty_master_fd;
a0e16eb1 26static int pty_child_pid;
27static sig_atomic_t pty_child_dead;
6169c758 28char **pty_argv;
054d8535 29
a0e16eb1 30int pty_child_is_dead(void)
31{
32 return pty_child_dead;
33}
34
1709795f 35static void pty_size(void);
36
a0e16eb1 37static void sigchld_handler(int signum)
38{
39 pid_t pid;
40 int status;
41 pid = waitpid(-1, &status, WNOHANG);
42 if (pid == pty_child_pid && (WIFEXITED(status) || WIFSIGNALED(status)))
43 pty_child_dead = TRUE;
44}
45
1709795f 46/*
47 * Called to set up the pty.
48 *
49 * Returns an error message, or NULL on success.
50 *
51 * Also places the canonical host name into `realhost'. It must be
52 * freed by the caller.
53 */
54static char *pty_init(char *host, int port, char **realhost, int nodelay)
55{
054d8535 56 int slavefd;
57 char name[FILENAME_MAX];
d37c2d81 58 pid_t pid, pgrp;
054d8535 59
60 pty_master_fd = open("/dev/ptmx", O_RDWR);
61
62 if (pty_master_fd < 0) {
63 perror("/dev/ptmx: open");
64 exit(1);
65 }
66
67 if (grantpt(pty_master_fd) < 0) {
68 perror("grantpt");
69 exit(1);
70 }
71
72 if (unlockpt(pty_master_fd) < 0) {
73 perror("unlockpt");
74 exit(1);
75 }
76
77 name[FILENAME_MAX-1] = '\0';
78 strncpy(name, ptsname(pty_master_fd), FILENAME_MAX-1);
79
054d8535 80 /*
81 * Fork and execute the command.
82 */
83 pid = fork();
84 if (pid < 0) {
85 perror("fork");
88e6b9ca 86 exit(1);
054d8535 87 }
88
89 if (pid == 0) {
90 int i;
91 /*
92 * We are the child.
93 */
d37c2d81 94
95 slavefd = open(name, O_RDWR);
96 if (slavefd < 0) {
97 perror("slave pty: open");
98 exit(1);
99 }
100
054d8535 101 close(pty_master_fd);
102 close(0);
103 close(1);
104 close(2);
105 fcntl(slavefd, F_SETFD, 0); /* don't close on exec */
106 dup2(slavefd, 0);
107 dup2(slavefd, 1);
108 dup2(slavefd, 2);
109 setsid();
d37c2d81 110 ioctl(slavefd, TIOCSCTTY, 1);
111 pgrp = getpid();
112 tcsetpgrp(slavefd, pgrp);
113 setpgrp();
114 close(open(name, O_WRONLY, 0));
054d8535 115 setpgrp();
054d8535 116 /* Close everything _else_, for tidiness. */
117 for (i = 3; i < 1024; i++)
118 close(i);
fe9548aa 119 {
120 char term_env_var[10 + sizeof(cfg.termtype)];
121 sprintf(term_env_var, "TERM=%s", cfg.termtype);
122 putenv(term_env_var);
123 }
6169c758 124 if (pty_argv)
125 execvp(pty_argv[0], pty_argv);
126 else
127 execl(getenv("SHELL"), getenv("SHELL"), NULL);
054d8535 128 /*
129 * If we're here, exec has gone badly foom.
130 */
131 perror("exec");
132 exit(127);
133 } else {
134 close(slavefd);
a0e16eb1 135 pty_child_pid = pid;
136 pty_child_dead = FALSE;
137 signal(SIGCHLD, sigchld_handler);
054d8535 138 }
139
1709795f 140 return NULL;
141}
142
143/*
144 * Called to send data down the pty.
145 */
146static int pty_send(char *buf, int len)
147{
054d8535 148 while (len > 0) {
149 int ret = write(pty_master_fd, buf, len);
150 if (ret < 0) {
151 perror("write pty master");
152 exit(1);
153 }
154 buf += ret;
155 len -= ret;
156 }
1709795f 157 return 0;
158}
159
160/*
161 * Called to query the current socket sendability status.
162 */
163static int pty_sendbuffer(void)
164{
165 return 0;
166}
167
168/*
169 * Called to set the size of the window
170 */
171static void pty_size(void)
172{
88e6b9ca 173 struct winsize size;
174
175 size.ws_row = (unsigned short)rows;
176 size.ws_col = (unsigned short)cols;
177 ioctl(pty_master_fd, TIOCSWINSZ, (void *)&size);
1709795f 178 return;
179}
180
181/*
182 * Send special codes.
183 */
184static void pty_special(Telnet_Special code)
185{
186 /* Do nothing! */
187 return;
188}
189
190static Socket pty_socket(void)
191{
192 return NULL; /* shouldn't ever be needed */
193}
194
195static int pty_sendok(void)
196{
197 return 1;
198}
199
200static void pty_unthrottle(int backlog)
201{
202 /* do nothing */
203}
204
205static int pty_ldisc(int option)
206{
207 return 0; /* neither editing nor echoing */
208}
209
210static int pty_exitcode(void)
211{
212 /* Shouldn't ever be required */
213 return 0;
214}
215
216Backend pty_backend = {
217 pty_init,
218 pty_send,
219 pty_sendbuffer,
220 pty_size,
221 pty_special,
222 pty_socket,
223 pty_exitcode,
224 pty_sendok,
225 pty_ldisc,
226 pty_unthrottle,
227 1
228};