2 #define _XOPEN_SOURCE_EXTENDED
13 #include <sys/types.h>
15 #include <sys/ioctl.h>
27 static int pty_child_pid
;
28 static sig_atomic_t pty_child_dead
;
31 int pty_child_is_dead(void)
33 return pty_child_dead
;
36 static void pty_size(void);
38 static void sigchld_handler(int signum
)
42 pid
= waitpid(-1, &status
, WNOHANG
);
43 if (pid
== pty_child_pid
&& (WIFEXITED(status
) || WIFSIGNALED(status
)))
44 pty_child_dead
= TRUE
;
48 * Called to set up the pty.
50 * Returns an error message, or NULL on success.
52 * Also places the canonical host name into `realhost'. It must be
53 * freed by the caller.
55 static char *pty_init(char *host
, int port
, char **realhost
, int nodelay
)
58 char name
[FILENAME_MAX
];
63 const char chars1
[] = "pqrstuvwxyz";
64 const char chars2
[] = "0123456789abcdef";
68 for (p1
= chars1
; *p1
; p1
++)
69 for (p2
= chars2
; *p2
; p2
++) {
70 sprintf(master_name
, "/dev/pty%c%c", *p1
, *p2
);
71 pty_master_fd
= open(master_name
, O_RDWR
);
72 if (pty_master_fd
>= 0) {
74 access(master_name
, R_OK
| W_OK
) == 0)
80 /* If we get here, we couldn't get a tty at all. */
81 fprintf(stderr
, "pterm: unable to open a pseudo-terminal device\n");
85 strcpy(name
, master_name
);
86 name
[5] = 't'; /* /dev/ptyXX -> /dev/ttyXX */
89 pty_master_fd
= open("/dev/ptmx", O_RDWR
);
91 if (pty_master_fd
< 0) {
92 perror("/dev/ptmx: open");
96 if (grantpt(pty_master_fd
) < 0) {
101 if (unlockpt(pty_master_fd
) < 0) {
106 name
[FILENAME_MAX
-1] = '\0';
107 strncpy(name
, ptsname(pty_master_fd
), FILENAME_MAX
-1);
111 * Fork and execute the command.
125 slavefd
= open(name
, O_RDWR
);
127 perror("slave pty: open");
132 /* We need to chown/chmod the /dev/ttyXX device. */
134 struct group
*gp
= getgrnam("tty");
135 fchown(slavefd
, getuid(), gp ? gp
->gr_gid
: -1);
136 fchmod(slavefd
, 0600);
140 close(pty_master_fd
);
144 fcntl(slavefd
, F_SETFD
, 0); /* don't close on exec */
149 ioctl(slavefd
, TIOCSCTTY
, 1);
151 tcsetpgrp(slavefd
, pgrp
);
153 close(open(name
, O_WRONLY
, 0));
155 /* In case we were setgid-utmp or setuid-root, drop privs. */
158 /* Close everything _else_, for tidiness. */
159 for (i
= 3; i
< 1024; i
++)
162 char term_env_var
[10 + sizeof(cfg
.termtype
)];
163 sprintf(term_env_var
, "TERM=%s", cfg
.termtype
);
164 putenv(term_env_var
);
167 execvp(pty_argv
[0], pty_argv
);
169 execl(getenv("SHELL"), getenv("SHELL"), NULL
);
171 * If we're here, exec has gone badly foom.
178 pty_child_dead
= FALSE
;
179 signal(SIGCHLD
, sigchld_handler
);
186 * Called to send data down the pty.
188 static int pty_send(char *buf
, int len
)
191 int ret
= write(pty_master_fd
, buf
, len
);
193 perror("write pty master");
203 * Called to query the current socket sendability status.
205 static int pty_sendbuffer(void)
211 * Called to set the size of the window
213 static void pty_size(void)
217 size
.ws_row
= (unsigned short)rows
;
218 size
.ws_col
= (unsigned short)cols
;
219 ioctl(pty_master_fd
, TIOCSWINSZ
, (void *)&size
);
224 * Send special codes.
226 static void pty_special(Telnet_Special code
)
232 static Socket
pty_socket(void)
234 return NULL
; /* shouldn't ever be needed */
237 static int pty_sendok(void)
242 static void pty_unthrottle(int backlog
)
247 static int pty_ldisc(int option
)
249 return 0; /* neither editing nor echoing */
252 static int pty_exitcode(void)
254 /* Shouldn't ever be required */
258 Backend pty_backend
= {