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