1 /*
2     dtach - A simple program that emulates the detach feature of screen.
3     Copyright (C) 2004-2016 Ned T. Crigler
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 #include "dtach.h"
20 
21 /* The pty struct - The pty information is stored here. */
22 struct pty
23 {
24 	/* File descriptor of the pty */
25 	int fd;
26 #ifdef BROKEN_MASTER
27 	/* File descriptor of the slave side of the pty. For broken systems. */
28 	int slave;
29 #endif
30 	/* Process id of the child. */
31 	pid_t pid;
32 	/* The terminal parameters of the pty. Old and new for comparision
33 	** purposes. */
34 	struct termios term;
35 	/* The current window size of the pty. */
36 	struct winsize ws;
37 };
38 
39 /* A connected client */
40 struct client
41 {
42 	/* The next client in the linked list. */
43 	struct client *next;
44 	/* The previous client in the linked list. */
45 	struct client **pprev;
46 	/* File descriptor of the client. */
47 	int fd;
48 	/* Whether or not the client is attached. */
49 	int attached;
50 };
51 
52 /* The list of connected clients. */
53 static struct client *clients;
54 /* The pseudo-terminal created for the child process. */
55 static struct pty the_pty;
56 /* The mode of the socket */
57 static mode_t socket_mode;
58 
59 #ifndef HAVE_FORKPTY
60 pid_t forkpty(int *amaster, char *name, struct termios *termp,
61 	struct winsize *winp);
62 #endif
63 
64 /* Unlink the socket */
65 static void
unlink_socket(void)66 unlink_socket(void)
67 {
68 	unlink(sockname);
69 }
70 
71 /* Check the actual mode of the socket */
72 static void
check_socket_mode(int has_attached_client)73 check_socket_mode(int has_attached_client)
74 {
75 	if (has_attached_client && ((socket_mode & 0100) != 0100)) {
76 		socket_mode |= 0100;
77 		chmod(sockname, socket_mode);
78 	} else if (!has_attached_client && ((socket_mode & 0100) == 0100)) {
79 		socket_mode &= ~0100;
80 		chmod(sockname, socket_mode);
81 	}
82 }
83 
84 /* Signal */
85 static RETSIGTYPE
die(int sig)86 die(int sig)
87 {
88 	/* Well, the child died. */
89 	if (sig == SIGCHLD)
90 	{
91 #ifdef BROKEN_MASTER
92 		/* Damn you Solaris! */
93 		close(the_pty.fd);
94 #endif
95 		return;
96 	}
97 	exit(1);
98 }
99 
100 /* Sets a file descriptor to non-blocking mode. */
101 static int
setnonblocking(int fd)102 setnonblocking(int fd)
103 {
104 	int flags;
105 
106 #if defined(O_NONBLOCK)
107 	flags = fcntl(fd, F_GETFL);
108 	if (flags < 0 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
109 		return -1;
110 	return 0;
111 #elif defined(FIONBIO)
112 	flags = 1;
113 	if (ioctl(fd, FIONBIO, &flags) < 0)
114 		return -1;
115 	return 0;
116 #else
117 #warning Do not know how to set non-blocking mode.
118 	return 0;
119 #endif
120 }
121 
122 /* Initialize the pty structure. */
123 static int
init_pty(char ** argv,int statusfd)124 init_pty(char **argv, int statusfd)
125 {
126 	/* Use the original terminal's settings. We don't have to set the
127 	** window size here, because the attacher will send it in a packet. */
128 	the_pty.term = orig_term;
129 	memset(&the_pty.ws, 0, sizeof(struct winsize));
130 
131 	/* Create the pty process */
132 	if (!dont_have_tty)
133 		the_pty.pid = forkpty(&the_pty.fd, NULL, &the_pty.term, NULL);
134 	else
135 		the_pty.pid = forkpty(&the_pty.fd, NULL, NULL, NULL);
136 	if (the_pty.pid < 0)
137 		return -1;
138 	else if (the_pty.pid == 0)
139 	{
140 		/* Child.. Execute the program. */
141 		execvp(*argv, argv);
142 
143 		/* Report the error to statusfd if we can, or stdout if we
144 		** can't. */
145 		if (statusfd != -1)
146 			dup2(statusfd, 1);
147 		else
148 			printf(EOS "\r\n");
149 
150 		printf("%s: could not execute %s: %s\r\n", progname,
151 		       *argv, strerror(errno));
152 		fflush(stdout);
153 		_exit(127);
154 	}
155 	/* Parent.. Finish up and return */
156 #ifdef BROKEN_MASTER
157 	{
158 		char *buf;
159 
160 		buf = ptsname(the_pty.fd);
161 		the_pty.slave = open(buf, O_RDWR|O_NOCTTY);
162 	}
163 #endif
164 	return 0;
165 }
166 
167 /* Send a signal to the slave side of a pseudo-terminal. */
168 static void
killpty(struct pty * pty,int sig)169 killpty(struct pty *pty, int sig)
170 {
171 	pid_t pgrp = -1;
172 
173 #ifdef TIOCSIGNAL
174 	if (ioctl(pty->fd, TIOCSIGNAL, sig) >= 0)
175 		return;
176 #endif
177 #ifdef TIOCSIG
178 	if (ioctl(pty->fd, TIOCSIG, sig) >= 0)
179 		return;
180 #endif
181 #ifdef TIOCGPGRP
182 #ifdef BROKEN_MASTER
183 	if (ioctl(pty->slave, TIOCGPGRP, &pgrp) >= 0 && pgrp != -1 &&
184 		kill(-pgrp, sig) >= 0)
185 		return;
186 #endif
187 	if (ioctl(pty->fd, TIOCGPGRP, &pgrp) >= 0 && pgrp != -1 &&
188 		kill(-pgrp, sig) >= 0)
189 		return;
190 #endif
191 
192 	/* Fallback using the child's pid. */
193 	kill(-pty->pid, sig);
194 }
195 
196 /* Creates a new unix domain socket. */
197 static int
create_socket(char * name)198 create_socket(char *name)
199 {
200 	int s;
201 	struct sockaddr_un sockun;
202 
203 	if (strlen(name) > sizeof(sockun.sun_path) - 1)
204 	{
205 		errno = ENAMETOOLONG;
206 		return -1;
207 	}
208 
209 	s = socket(PF_UNIX, SOCK_STREAM, 0);
210 	if (s < 0)
211 		return -1;
212 	sockun.sun_family = AF_UNIX;
213 	strcpy(sockun.sun_path, name);
214 	if (bind(s, (struct sockaddr*)&sockun, sizeof(sockun)) < 0)
215 	{
216 		close(s);
217 		return -1;
218 	}
219 	if (listen(s, 128) < 0)
220 	{
221 		close(s);
222 		return -1;
223 	}
224 	if (setnonblocking(s) < 0)
225 	{
226 		close(s);
227 		return -1;
228 	}
229 	/* chmod it to prevent any suprises */
230 	socket_mode = 0600;
231 	if (chmod(name, socket_mode) < 0)
232 	{
233 		close(s);
234 		return -1;
235 	}
236 	return s;
237 }
238 
239 /* Update the modes on the socket. */
240 static void
update_socket_modes(int exec)241 update_socket_modes(int exec)
242 {
243 	struct stat st;
244 	mode_t newmode;
245 
246 	if (stat(sockname, &st) < 0)
247 		return;
248 
249 	if (exec)
250 		newmode = st.st_mode | S_IXUSR;
251 	else
252 		newmode = st.st_mode & ~S_IXUSR;
253 
254 	if (st.st_mode != newmode)
255 		chmod(sockname, newmode);
256 }
257 
258 /* Process activity on the pty - Input and terminal changes are sent out to
259 ** the attached clients. If the pty goes away, we die. */
260 static void
pty_activity(int s)261 pty_activity(int s)
262 {
263 	unsigned char buf[BUFSIZE];
264 	ssize_t len;
265 	struct client *p;
266 	fd_set readfds, writefds;
267 	int highest_fd, nclients;
268 
269 	/* Read the pty activity */
270 	len = read(the_pty.fd, buf, sizeof(buf));
271 
272 	/* Error -> die */
273 	if (len <= 0)
274 		exit(1);
275 
276 #ifdef BROKEN_MASTER
277 	/* Get the current terminal settings. */
278 	if (tcgetattr(the_pty.slave, &the_pty.term) < 0)
279 		exit(1);
280 #else
281 	/* Get the current terminal settings. */
282 	if (tcgetattr(the_pty.fd, &the_pty.term) < 0)
283 		exit(1);
284 #endif
285 
286 top:
287 	/*
288 	** Wait until at least one client is writable. Also wait on the control
289 	** socket in case a new client tries to connect.
290 	*/
291 	FD_ZERO(&readfds);
292 	FD_ZERO(&writefds);
293 	FD_SET(s, &readfds);
294 	highest_fd = s;
295 	for (p = clients, nclients = 0; p; p = p->next)
296 	{
297 		if (!p->attached)
298 			continue;
299 		FD_SET(p->fd, &writefds);
300 		if (p->fd > highest_fd)
301 			highest_fd = p->fd;
302 		nclients++;
303 	}
304 	if (nclients == 0)
305 		return;
306 	if (select(highest_fd + 1, &readfds, &writefds, NULL, NULL) < 0)
307 		return;
308 
309 	/* Send the data out to the clients. */
310 	for (p = clients, nclients = 0; p; p = p->next)
311 	{
312 		ssize_t written;
313 
314 		if (!FD_ISSET(p->fd, &writefds))
315 			continue;
316 
317 		written = 0;
318 		while (written < len)
319 		{
320 			ssize_t n = write(p->fd, buf + written, len - written);
321 
322 			if (n > 0)
323 			{
324 				written += n;
325 				continue;
326 			}
327 			else if (n < 0 && errno == EINTR)
328 				continue;
329 			else if (n < 0 && errno != EAGAIN)
330 				nclients = -1;
331 			break;
332 		}
333 		if (nclients != -1 && written == len)
334 			nclients++;
335 	}
336 
337 	/* Try again if nothing happened. */
338 	if (!FD_ISSET(s, &readfds) && nclients == 0)
339 		goto top;
340 }
341 
342 /* Process activity on the control socket */
343 static void
control_activity(int s)344 control_activity(int s)
345 {
346 	int fd;
347 	struct client *p;
348 
349 	/* Accept the new client and link it in. */
350 	fd = accept(s, NULL, NULL);
351 	if (fd < 0)
352 		return;
353 	else if (setnonblocking(fd) < 0)
354 	{
355 		close(fd);
356 		return;
357 	}
358 
359 	/* Link it in. */
360 	p = malloc(sizeof(struct client));
361 	p->fd = fd;
362 	p->attached = 0;
363 	p->pprev = &clients;
364 	p->next = *(p->pprev);
365 	if (p->next)
366 		p->next->pprev = &p->next;
367 	*(p->pprev) = p;
368 }
369 
370 /* Process activity from a client. */
371 static void
client_activity(struct client * p)372 client_activity(struct client *p)
373 {
374 	ssize_t len;
375 	struct packet pkt;
376 
377 	/* Read the activity. */
378 	len = read(p->fd, &pkt, sizeof(struct packet));
379 	if (len < 0 && (errno == EAGAIN || errno == EINTR))
380 		return;
381 
382 	/* Close the client on an error. */
383 	if (len <= 0)
384 	{
385 		close(p->fd);
386 		if (p->next)
387 			p->next->pprev = p->pprev;
388 		*(p->pprev) = p->next;
389 		free(p);
390 		return;
391 	}
392 
393 	/* Push out data to the program. */
394 	if (pkt.type == MSG_PUSH)
395 	{
396 		if (pkt.len <= sizeof(pkt.u.buf))
397 			write(the_pty.fd, pkt.u.buf, pkt.len);
398 	}
399 
400 	/* Attach or detach from the program. */
401 	else if (pkt.type == MSG_ATTACH)
402 		p->attached = 1;
403 	else if (pkt.type == MSG_DETACH)
404 		p->attached = 0;
405 
406 	/* Window size change request, without a forced redraw. */
407 	else if (pkt.type == MSG_WINCH)
408 	{
409 		the_pty.ws = pkt.u.ws;
410 		ioctl(the_pty.fd, TIOCSWINSZ, &the_pty.ws);
411 	}
412 
413 	/* Force a redraw using a particular method. */
414 	else if (pkt.type == MSG_REDRAW)
415 	{
416 		int method = pkt.len;
417 
418 		/* If the client didn't specify a particular method, use
419 		** whatever we had on startup. */
420 		if (method == REDRAW_UNSPEC)
421 			method = redraw_method;
422 		if (method == REDRAW_NONE)
423 			return;
424 
425 		/* Set the window size. */
426 		the_pty.ws = pkt.u.ws;
427 		ioctl(the_pty.fd, TIOCSWINSZ, &the_pty.ws);
428 
429 		/* Send a ^L character if the terminal is in no-echo and
430 		** character-at-a-time mode. */
431 		if (method == REDRAW_CTRL_L)
432 		{
433 			char c = '\f';
434 
435                 	if (((the_pty.term.c_lflag & (ECHO|ICANON)) == 0) &&
436                         	(the_pty.term.c_cc[VMIN] == 1))
437 			{
438 				write(the_pty.fd, &c, 1);
439 			}
440 		}
441 		/* Send a WINCH signal to the program. */
442 		else if (method == REDRAW_WINCH)
443 		{
444 			killpty(&the_pty, SIGWINCH);
445 		}
446 	}
447 }
448 
449 /* The master process - It watches over the pty process and the attached */
450 /* clients. */
451 static void
master_process(int s,char ** argv,int waitattach,int statusfd)452 master_process(int s, char **argv, int waitattach, int statusfd)
453 {
454 	struct client *p, *next;
455 	fd_set readfds;
456 	int highest_fd;
457 	int nullfd;
458 
459 	int has_attached_client = 0;
460 
461 	/* Okay, disassociate ourselves from the original terminal, as we
462 	** don't care what happens to it. */
463 	setsid();
464 
465 	/* Set a trap to unlink the socket when we die. */
466 	atexit(unlink_socket);
467 
468 	/* Create a pty in which the process is running. */
469 	signal(SIGCHLD, die);
470 	if (init_pty(argv, statusfd) < 0)
471 	{
472 		if (statusfd != -1)
473 			dup2(statusfd, 1);
474 		if (errno == ENOENT)
475 			printf("%s: Could not find a pty.\n", progname);
476 		else
477 			printf("%s: init_pty: %s\n", progname, strerror(errno));
478 		exit(1);
479 	}
480 
481 	/* Set up some signals. */
482 	signal(SIGPIPE, SIG_IGN);
483 	signal(SIGXFSZ, SIG_IGN);
484 	signal(SIGHUP, SIG_IGN);
485 	signal(SIGTTIN, SIG_IGN);
486 	signal(SIGTTOU, SIG_IGN);
487 	signal(SIGINT, die);
488 	signal(SIGTERM, die);
489 
490 	/* Close statusfd, since we don't need it anymore. */
491 	if (statusfd != -1)
492 		close(statusfd);
493 
494 	/* Make sure stdin/stdout/stderr point to /dev/null. We are now a
495 	** daemon. */
496 	nullfd = open("/dev/null", O_RDWR);
497 	dup2(nullfd, 0);
498 	dup2(nullfd, 1);
499 	dup2(nullfd, 2);
500 	if (nullfd > 2)
501 		close(nullfd);
502 
503 	/* Loop forever. */
504 	while (1)
505 	{
506 		int new_has_attached_client = 0;
507 
508 		/* Re-initialize the file descriptor set for select. */
509 		FD_ZERO(&readfds);
510 		FD_SET(s, &readfds);
511 		highest_fd = s;
512 
513 		/*
514 		** When waitattach is set, wait until the client attaches
515 		** before trying to read from the pty.
516 		*/
517 		if (waitattach)
518 		{
519 			if (clients && clients->attached)
520 				waitattach = 0;
521 		}
522 		else
523 		{
524 			FD_SET(the_pty.fd, &readfds);
525 			if (the_pty.fd > highest_fd)
526 				highest_fd = the_pty.fd;
527 		}
528 
529 		for (p = clients; p; p = p->next)
530 		{
531 			FD_SET(p->fd, &readfds);
532 			if (p->fd > highest_fd)
533 				highest_fd = p->fd;
534 
535 			if (p->attached)
536 				new_has_attached_client = 1;
537 		}
538 
539 		/* chmod the socket if necessary. */
540 		if (has_attached_client != new_has_attached_client)
541 		{
542 			update_socket_modes(new_has_attached_client);
543 			has_attached_client = new_has_attached_client;
544 		}
545 
546 		/* Wait for something to happen. */
547 		if (select(highest_fd + 1, &readfds, NULL, NULL, NULL) < 0)
548 		{
549 			if (errno == EINTR || errno == EAGAIN)
550 				continue;
551 			exit(1);
552 		}
553 
554 		/* New client? */
555 		if (FD_ISSET(s, &readfds))
556 			control_activity(s);
557 		/* Activity on a client? */
558 		for (p = clients; p; p = next)
559 		{
560 			next = p->next;
561 			if (FD_ISSET(p->fd, &readfds))
562 				client_activity(p);
563 		}
564 		/* pty activity? */
565 		if (FD_ISSET(the_pty.fd, &readfds))
566 			pty_activity(s);
567 	}
568 }
569 
570 int
master_main(char ** argv,int waitattach,int dontfork)571 master_main(char **argv, int waitattach, int dontfork)
572 {
573 	int fd[2] = {-1, -1};
574 	int s;
575 	pid_t pid;
576 
577 	/* Use a default redraw method if one hasn't been specified yet. */
578 	if (redraw_method == REDRAW_UNSPEC)
579 		redraw_method = REDRAW_CTRL_L;
580 
581 	/* Create the unix domain socket. */
582 	s = create_socket(sockname);
583 	if (s < 0 && errno == ENAMETOOLONG)
584 	{
585 		char *slash = strrchr(sockname, '/');
586 
587 		/* Try to shorten the socket's path name by using chdir. */
588 		if (slash)
589 		{
590 			int dirfd = open(".", O_RDONLY);
591 
592 			if (dirfd >= 0)
593 			{
594 				*slash = '\0';
595 				if (chdir(sockname) >= 0)
596 				{
597 					s = create_socket(slash + 1);
598 					fchdir(dirfd);
599 				}
600 				*slash = '/';
601 				close(dirfd);
602 			}
603 		}
604 	}
605 	if (s < 0)
606 	{
607 		printf("%s: %s: %s\n", progname, sockname, strerror(errno));
608 		return 1;
609 	}
610 
611 #if defined(F_SETFD) && defined(FD_CLOEXEC)
612 	fcntl(s, F_SETFD, FD_CLOEXEC);
613 
614 	/* If FD_CLOEXEC works, create a pipe and use it to report any errors
615 	** that occur while trying to execute the program. */
616 	if (dontfork)
617 	{
618 		fd[1] = dup(2);
619 		if (fcntl(fd[1], F_SETFD, FD_CLOEXEC) < 0)
620 		{
621 			close(fd[1]);
622 			fd[1] = -1;
623 		}
624 	}
625 	else if (pipe(fd) >= 0)
626 	{
627 		if (fcntl(fd[0], F_SETFD, FD_CLOEXEC) < 0 ||
628 		    fcntl(fd[1], F_SETFD, FD_CLOEXEC) < 0)
629 		{
630 			close(fd[0]);
631 			close(fd[1]);
632 			fd[0] = fd[1] = -1;
633 		}
634 	}
635 #endif
636 
637 	if (dontfork)
638 	{
639 		master_process(s, argv, waitattach, fd[1]);
640 		return 0;
641 	}
642 
643 	/* Fork off so we can daemonize and such */
644 	pid = fork();
645 	if (pid < 0)
646 	{
647 		printf("%s: fork: %s\n", progname, strerror(errno));
648 		unlink_socket();
649 		return 1;
650 	}
651 	else if (pid == 0)
652 	{
653 		/* Child - this becomes the master */
654 		if (fd[0] != -1)
655 			close(fd[0]);
656 		master_process(s, argv, waitattach, fd[1]);
657 		return 0;
658 	}
659 	/* Parent - just return. */
660 
661 #if defined(F_SETFD) && defined(FD_CLOEXEC)
662 	/* Check if an error occurred while trying to execute the program. */
663 	if (fd[0] != -1)
664 	{
665 		char buf[1024];
666 		ssize_t len;
667 
668 		close(fd[1]);
669 		len = read(fd[0], buf, sizeof(buf));
670 		if (len > 0)
671 		{
672 			write(2, buf, len);
673 			kill(pid, SIGTERM);
674 			return 1;
675 		}
676 		close(fd[0]);
677 	}
678 #endif
679 	close(s);
680 	return 0;
681 }
682 
683 /* BSDish functions for systems that don't have them. */
684 #ifndef HAVE_OPENPTY
685 #define HAVE_OPENPTY
686 /* openpty: Use /dev/ptmx and Unix98 if we have it. */
687 #if defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT) && defined(HAVE_UNLOCKPT)
688 int
openpty(int * amaster,int * aslave,char * name,struct termios * termp,struct winsize * winp)689 openpty(int *amaster, int *aslave, char *name, struct termios *termp,
690 	struct winsize *winp)
691 {
692 	int master, slave;
693 	char *buf;
694 
695 #ifdef _AIX
696 	master = open("/dev/ptc", O_RDWR|O_NOCTTY);
697 	if (master < 0)
698 		return -1;
699 	buf = ttyname(master);
700 	if (!buf)
701 		return -1;
702 
703 	slave = open(buf, O_RDWR|O_NOCTTY);
704 	if (slave < 0)
705 		return -1;
706 #else
707 	master = open("/dev/ptmx", O_RDWR);
708 	if (master < 0)
709 		return -1;
710 	if (grantpt(master) < 0)
711 		return -1;
712 	if (unlockpt(master) < 0)
713 		return -1;
714 	buf = ptsname(master);
715 	if (!buf)
716 		return -1;
717 
718 	slave = open(buf, O_RDWR|O_NOCTTY);
719 	if (slave < 0)
720 		return -1;
721 
722 #ifdef I_PUSH
723 	if (ioctl(slave, I_PUSH, "ptem") < 0)
724 		return -1;
725 	if (ioctl(slave, I_PUSH, "ldterm") < 0)
726 		return -1;
727 #endif
728 #endif
729 
730 	*amaster = master;
731 	*aslave = slave;
732 	if (name)
733 		strcpy(name, buf);
734 	if (termp)
735 		tcsetattr(slave, TCSAFLUSH, termp);
736 	if (winp)
737 		ioctl(slave, TIOCSWINSZ, winp);
738 	return 0;
739 }
740 #else
741 #error Do not know how to define openpty.
742 #endif
743 #endif
744 
745 #ifndef HAVE_FORKPTY
746 #if defined(HAVE_OPENPTY)
747 pid_t
forkpty(int * amaster,char * name,struct termios * termp,struct winsize * winp)748 forkpty(int *amaster, char *name, struct termios *termp,
749 	struct winsize *winp)
750 {
751 	pid_t pid;
752 	int master, slave;
753 
754 	if (openpty(&master, &slave, name, termp, winp) < 0)
755 		return -1;
756 	*amaster = master;
757 
758 	/* Fork off... */
759 	pid = fork();
760 	if (pid < 0)
761 		return -1;
762 	else if (pid == 0)
763 	{
764 		char *buf;
765 		int fd;
766 
767 		setsid();
768 #ifdef TIOCSCTTY
769 		buf = NULL;
770 		if (ioctl(slave, TIOCSCTTY, NULL) < 0)
771 			_exit(1);
772 #elif defined(_AIX)
773 		fd = open("/dev/tty", O_RDWR|O_NOCTTY);
774 		if (fd >= 0)
775 		{
776 			ioctl(fd, TIOCNOTTY, NULL);
777 			close(fd);
778 		}
779 
780 		buf = ttyname(master);
781 		fd = open(buf, O_RDWR);
782 		close(fd);
783 
784 		fd = open("/dev/tty", O_WRONLY);
785 		if (fd < 0)
786 			_exit(1);
787 		close(fd);
788 
789 		if (termp && tcsetattr(slave, TCSAFLUSH, termp) == -1)
790 			_exit(1);
791 		if (ioctl(slave, TIOCSWINSZ, winp) == -1)
792 			_exit(1);
793 #else
794 		buf = ptsname(master);
795 		fd = open(buf, O_RDWR);
796 		close(fd);
797 #endif
798 		dup2(slave, 0);
799 		dup2(slave, 1);
800 		dup2(slave, 2);
801 
802 		if (slave > 2)
803 			close(slave);
804 		close(master);
805 		return 0;
806 	}
807 	else
808 	{
809 		close(slave);
810 		return pid;
811 	}
812 }
813 #else
814 #error Do not know how to define forkpty.
815 #endif
816 #endif
817